2

I'm using RP Niemeyer's Kendo-Knockout bindings and I can get things to work alright. The issue I currently have is attempting to filter on an observable column using Kendo menu filtering customization.

The Kendo filterable property works fine for a non-observable column ('color') but I can't get it to work for the observable column ('fruit').

For example, when I click the filter icon to filter the fruit column on 'apple' the console.log shows the error:

Uncaught TypeError: (d.fruit || "").toLowerCase is not a function

Instead of binding to an observable array (self.items()) I could use the following approach:

self.items.asJS = ko.computed(function() {
return ko.toJS(self.items());

}, self);

But the problem here is that data would be disconnected to self.items() observable array defeating the purpose of MVVM. So this is not the solution I'm after. Or maybe there's no 'can do' between Knockout and Kendo UI for the moment.

Here's the HTML:

<div style="width:400px; height:150px; font-size:14px" data-bind="kendoGrid:

    {data: items,
    rowTemplate: 'itemsTmpl', useKOTemplates: true,
    filterable: { extra: false},
    columns: [
    {field: 'id', title: 'ID', type: 'number', width: '30px'},
    {field: 'color', title: 'Color', type: 'string', width:'120px'},
    {field: 'fruit' , title: 'Fruit', type: 'string', width:'95%'}
    ]
    }">

</div>

This is the ko view model code:

<script id="itemsTmpl" type="text/html">

    <tr style="height:5px" data-bind="focus: $root.selectRow ">
        <td data-bind="text: id"></td>
        <td>
            <span style="width:95%" data-bind="text:color"></span>
        </td>
        <td>
            <span style="width:95%" data-bind="text: fruit"></span>
        </td> 
    </tr>
</script>

<script type="text/javascript">

    var item = function (id, color, fruit) {
        var self = this;
        self.id = id;
        self.color = color;
        self.fruit = ko.observable(fruit);
    }

    var ViewModel = function () {

        var self = this;

        self.items = ko.observableArray([
        new item(1, 'black', 'apple'),
        new item(2, 'green', 'orange'),
        new item(3, 'yellow', 'banana')
        ]);

    };

    ko.applyBindings(new ViewModel());

</script>
user1309226
  • 739
  • 1
  • 10
  • 31

2 Answers2

2

I solved this issue by using Knockout ES5. Then, when assigning my data to my model, I used knockout-mapping with a mapping object like this:

        var dataMapper = {
            create: function(o) {
                return ko.track(o.data), o.data;
            }
        };
        ko.mapping.fromJS(json, dataMapper, self.data);

This makes the filtering and sorting work out of the box for the knockout kendo grid.

JoeWarwick
  • 105
  • 2
  • 8
0

When defining your columns, the field name is used to retrieve the value for sorting and filtering. So if the field name is fruit, this is called to get the value:

item.fruit

But since fruit is an observable, that won't work. We want the field name to be fruit() so that it is called like this:

item.fruit()

To make this work in your situation, update the columns definition to this:

columns: [
  {field: 'id', title: 'ID', type: 'number', width: '30px'},
  {field: 'color', title: 'Color', type: 'string', width:'120px'},
  {field: 'fruit()' , title: 'Fruit', type: 'string', width:'95%'}
]

The only thing that I changed was to add the parentheses to the field name for fruit.

CodeThug
  • 3,054
  • 1
  • 21
  • 17