1

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!

sanderd
  • 809
  • 4
  • 21
  • 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 Apr 19 '13 at 07:29

1 Answers1

2

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

cwohlman
  • 763
  • 6
  • 21
  • Indeed, the children-array itself _is_ being watched by KoGrid. The reason why I'm using this construction is that vm.bar is actually vm.selectedItem from a dropdown on top. As you've pointed out ko.mapping (or simply overwriting all fields, instead of an object pointer) might come to the rescue, but goes against the simplicity I tried to achieve. For now, going with the with-binding. Thx! – sanderd May 21 '13 at 12:00
  • In that case I agree, a with binding is the way to go. Glad to have helped. – cwohlman May 21 '13 at 16:40