2

I submit for your consideration, this fiddle: http://jsfiddle.net/alexdresko/HFFUL/5/

There are two identical grids in the HTML, but only one of them populates when you click the "Load" button.

Is this due to my own fundamental misunderstanding of knockout, or is it a jqxgrid problem?

Here's the code:

<a href="#" data-bind="click: load">Load</a>

<div class="aGrid" data-bind="jqxGrid: { source: Stuff().People, columns: [ {text: 'Name', datafield: 'Name'} ], autoheight: true, sortable: true, altrows: true, enabletooltips:true }"></div>
<div class="aGrid" data-bind="jqxGrid: { source: Stuff().People, columns: [ {text: 'Name', datafield: 'Name'} ], autoheight: true, sortable: true, altrows: true, enabletooltips:true }"></div>

var dataFromServer = {
    People: ko.observableArray([{
        Name: "George"
    }, {
        Name: "Scot"
    }])
};

var viewModel = function () {

    this.Stuff = ko.observable({});
    this.load = function () {
        this.Stuff(dataFromServer);

    };
};

$(function () {
    var vm = new viewModel();
    ko.applyBindings(vm);
});
Alex Dresko
  • 5,179
  • 3
  • 37
  • 57

2 Answers2

2

The problem is somewhere in source : Stuff().People because you explicitly get the value of the Stuff observable here and access the People property of that. Changing Stuff itself does not change this bound observable array.

However, there is a overall more elagant solution, where you also don't have to make the dataFromServer an observable itself:

HTML:

<a href="#" data-bind="click: load">Load</a>

<div class="aGrid" data-bind="jqxGrid: { source: Stuff.People, columns: [ {text: 'Name', datafield: 'Name'} ], autoheight: true, sortable: true, altrows: true, enabletooltips:true }"></div>
<div class="aGrid" data-bind="jqxGrid: { source: Stuff.People, columns: [ {text: 'Name', datafield: 'Name'} ], autoheight: true, sortable: true, altrows: true, enabletooltips:true }"></div>

JavaScript:

var dataFromServer = [{
        Name: "George"
    }, {
        Name: "Scot"
    }];

var viewModel = function () {

    this.Stuff = { People: ko.observableArray([]) }
    this.load = function () {
        for (i=0; i < dataFromServer.length; ++i) {
            this.Stuff.People.push(dataFromServer[i]);
        }

    };
};


$(function () {

    var vm = new viewModel();
    ko.applyBindings(vm);

});

Forked JSFiddle

Fabian Schmengler
  • 24,155
  • 9
  • 79
  • 111
  • I had a difficult time deciding if I should approve your answer or Matt's, but, ultimately, Matt's answer was first to solve the problem. Matt's answer also steered me in the direction of your answer on my own, so even though your answer is more thorough, I've awarded the points to Mat. I hope you understand. – Alex Dresko Feb 07 '13 at 15:12
0

Not sure about the cause, but when I wrapped your two grids in a div like this:

<div data-bind="if: Stuff().People">

It worked fine. Of course, this hides your grids altogether until you click load.

Fiddle

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • Hey nice! It'd be cool if someone could explain why this fixes the problem. Let me think about the implications before I award you the answer. – Alex Dresko Feb 06 '13 at 14:44
  • Seems like the binding of `Stuff().People` to your grid then does not happen until `Stuff().People` exists (see also my answer). But I doubt that this will work if you assign `Stuff(data)` a second time. – Fabian Schmengler Feb 06 '13 at 15:07
  • OK, tried it out, it still works. I'm still not sure, when *exactly* the bindings happen but it looks like they are re-evaluated in this case. – Fabian Schmengler Feb 06 '13 at 15:11
  • One thing that happens here is when the `if` is reevaluated to true (which it is when `Stuff().People` is truthy - i.e. it exists), knockout will recreate the DOM elements enclosed by it. – Matt Burland Feb 06 '13 at 18:11