Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a parent method from kendo template binding?

I have the following fiddle. I'm trying to call the parent method lowestMpgMsg for each of the elements inside the array cars. I have try using the following bindings with no luck:

data-bind="text: lowestMpgMsg()"
data-bind="text: parent.lowestMpgMsg()"
data-bind="text: parent().lowestMpgMsg()"
data-bind="text: parent().lowestMpgMsg"

Thank you!

Here is my html

<div class="container">
<div id="template-container" data-template="template" data-bind="source: cars"></div>
<script id="template" type="text/x-kendo-template">
    <div>
        <span data-bind="text: brand"></span> - 
        <span data-bind="text: mpg"></span> - 
        <span data-bind="text: lowestMpgMsg()"></span> - 
    </div>
</script>

and here is my javascript

var viewModel = kendo.observable({
    cars: [
        {brand: "Toyota", mpg: 22},
        {brand: "Mini", mpg: 32},
        {brand: "Honda", mpg: 23}
    ],
    lowestMpgMsg: function(e) {
        var sorted = this.cars.sort(function(a, b) {
            return a.mpg - b.mpg > 0;
        });

        return e.mpg > sorted[0].mpg ? "no" : "yes";
    }
});

kendo.bind($("#template-container"), viewModel);
like image 972
Ovi Avatar asked Jun 06 '14 20:06

Ovi


1 Answers

The short answer is that you don't have to--it calls the parent method on the parent automatically, reminiscent of how the prototype chain works. The longer answer is the correct syntax isn't one listed in your question AND the code has a subtle error with the way you're using this.

First, notice that bindings are not javascript. The MVVM overview in the documentation clarifies that you cannot invoke methods in bindings, so nothing with parenthesis is going to be legal syntax. Even if you could, you would have to call the parent method twice from a car instance:

var car = viewModel.cars[0];
var cars = car.parent();
var model = car.parent().parent();
var lowestFn = model.lowestMpgMsg.bind(model); //the bind makes this refer to the intended object 

This means you would need something to bind to something like parent().parent().lowestMpgMsg()

The good news is that data-bind="text: lowestMpgMsg" will behave like you want it to. It will call the item's parent().parent().lowestMpgMsg(). To see the basic parent chain working, changing the template to

    <script id="template" type="text/x-kendo-template">
        <div>
            <span data-bind="text: brand"></span> - 
            <span data-bind="text: mpg"></span> - 
            <span data-bind="text: lowestMpgMsg"></span> - 
        </div>
    </script>

and the model to

    var viewModel = kendo.observable({
        cars: [
            {brand: "Toyota", mpg: 22},
            {brand: "Mini", mpg: 32},
            {brand: "Honda", mpg: 23}
        ],
        lowestMpgMsg: function(e) {       
            return Math.random();
        }
    });

Now, let's get to why your lowestMpgMsg isn't working. Start by noticing that the method throws an exception on your viewmodel, but not in the object that is wrapped:

viewModel.lowestMpgMsg({mpg:15}); //throws exception

var notWrapped = {
    cars: [
        {brand: "Toyota", mpg: 22},
        {brand: "Mini", mpg: 32},
        {brand: "Honda", mpg: 23}
    ],
    lowestMpgMsg: function(e) {
        var sorted = this.cars.sort(function(a, b) {
            return a.mpg - b.mpg > 0;
        });
        return e.mpg > sorted[0].mpg ? "no" : "yes";
    }
}
notWrapped.lowestMpgMsg({mpg:15}); //no exception

When the lowestMpgMsg is invoked during binding, the this.cars refers to the same object as viewModel.cars and is an instanceof type kendo.data.ObservableArray, which does not have a sort method.

Finally, be sure to use a get method for the calculated field, so the MVVM framework knows to update it when dependencies change.

like image 86
Steve Clanton Avatar answered Oct 14 '22 04:10

Steve Clanton