1
votes

Context
I'm currently exploring KnockoutJS, combined with a KoGrid.
I have an object containing several fields (which are also bound to fields), and a list of child objects which I want to show in KoGrid.

jsfiddle
I've prepared a jsFiddle illustrating the issue I'm having:
http://jsfiddle.net/kPmAJ/4/

The issue:
My viewmodel contains an observable foo, containing the parent object.
In this parent object, there is a property children, which is an observableArray containing objects again.

The KoGrid is bound to $root.foo().children

This works if the array is filled before initializing the binding.
However, the object gets replaced afterwards (data is loaded through AJAX and can be re-loaded), and apparently the KoGrid items binding is lost.

I was thinking that, since the foo-object on my viewmodel is an observable, this would trigger KoGrid that is watching the array inside to update if foo gets replaced. This does work perfectly with a foreach-binding.

Apparently KoGrid doesn't trigger though.

--

Am I doing something wrong here, or have I hit an issue in KoGrid?

Code (for reference purposes. see fiddler ;))

var SampleObject = function (data) {
    this.id = new ko.observable(data ? data.id : null);
    this.children = new ko.observableArray([]);

    if(data) {
        var childrenMapped = [];
        $(data.children).each(
            function()  {
                childrenMapped.push(new SampleChildObject(this));
            }
        );
        this.children(childrenMapped);
    }
}

var SampleChildObject = function (data) {
    this.name = new ko.observable(data ? data.name : null);
};


var vm = {
    foo: new ko.observable('John Doe'),
    bar: new ko.observable(
            new SampleObject(
            {
                id: 1234,
                children: []
            })
        )
};

ko.applyBindings(vm);

// Returns from an AJAX-call instead, so can't be before applyBindings
vm.bar(new SampleObject(
            {
                id: 1234,
                children: [
                    { name: 'test1' },
                    { name: 'test2' },
                    { name: 'test3' }]
            }));

-

<div style="height: 500px;"
data-bind="koGrid: { data: bar().children }"></div>

<ul data-bind="foreach: bar().children">
    <li data-bind="text: name"></li>
</ul>

Thanks!

1
Wrapping the grid with a 'with: bar'-binding, and then binding the grid to just 'children', seems to work okay. Still wondering what's going on though. - sanderd

1 Answers

2
votes

What's happening is that the koGrid binding doesn't have an update handler, so it's not responding to any changes in bar.

The koGrid does watch the observable array children though, if you we're to replace the values in bar().children with those returned from your Ajax call the grid would update.

Like this:

function (data) {

    var childrenMapped = [];

    $(data.children).each(

        function()  {

            childrenMapped.push(new SampleChildObject(this));

});
    bar().children(childrenMapped);

    bar().id(data.id);

});

You should also checkout the mapping plugin which is supposed to solve this problem. ko mapping