简体   繁体   中英

knockout 'click' binding not working

I am trying to bind a click event to a list item. When I click on the list item below, it should fire up the updateCurrent function in the javascript, but it doesn't do anything.

note: I have used $parent.updateCurrent as I am in the currentCat context when I call the function and the updateCurrent function is in the ViewModel context.

HTML:

<div id="wrap" data-bind="with: currentCat">

    <div id="names">
        <ul data-bind="foreach: $parent.catNames">
            <!--Here, clicking on name doesn't fire updateCurrent-->
            <li data-bind="text: $data, click: $parent.updateCurrent"></li>
        </ul>
    </div>
</div>

JS:

var viewModel = function() {

    var self = this;
    this.catNames = ko.observableArray([]);
    this.catList = ko.observableArray([]);

    //cats is defined as a simple array of objects, having name
    cats.forEach(function(catObject) {
        self.catList.push(new cat(catObject));
        self.catNames.push(catObject.name);
    });

    //initially, set the currentCat to first cat
    this.currentCat = ko.observable(this.catList()[0]);

    //should run when the user click on the cat name in the list
    this.updateCurrent = function() {
        console.log("hello");
    }

};

I don't get any error when I click on the list name, but console doesn't log anything.

I believe I am not using the context properly, but can't figure out the exact issue here. Any help will be appreciated.

When you say $parent.catNames, you are referring to the ViewModel because it is an owned property of the immediate parent in the hierarchy. With the foreach binding, you are within a new context; therefore in $parent.updateCurrent, the immediate parent in the hierarchy becomes the item in catNames array.

You can use $root in this case as Viktor has mentioned but the safest and proper way to achieve this functionality is to climb the hierarchy one level at a time to obtain $parents[1].

$parent is equal to $parents[0] which is one of the catNames. $parents[1] will refer to the ViewModel.

Why not use $root?

Knockout will maintain your DOM and binding context much deeper than may be readily apparent. In template bindings, the $root context may refer to an object that isn't even in the HTML template!

<div data-bind="template: { name: 'sample', data: catNames }"></div>
<script type='text/html' id='sample'>
    <!-- ko foreach: $data -->
    <span data-bind="text: 'Cat ' + $index + ' of ' + $parents[0].length"></span>
    Returns "Cat 1 of 10"
    <!-- /ko -->

    <!-- ko foreach: $data -->
    <span data-bind="text: 'Cat ' + $index + ' of ' + $root.length"></span>
    Return "Cat 1 of undefined" because ViewModel has no length property!
    <!-- /ko -->
</script>

Binding context documentation: http://knockoutjs.com/documentation/binding-context.html

You are inside two levels of context. The with binding indicates that $data inside that div is currentCat . The foreach provides another level of context. $parent doesn't refer to the parent of an object, but the context outside this context. You could use $parents[1] .

When you say $parent.catNames , you're only inside the with context, so it does refer to catNames in ViewModel , since there's no other enclosing context. But where you say $parent.updateCurrent , you're jumping out of the foreach context up to the with context. And you wanted to jump one more.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM