Update Knockout.js Observable from JSON
Asked Answered
G

3

12

I'm attempt to establish a grid and update it with more records via JSON. In this simple example I am able to achieve the required functionality but I can only update / push one JSON record. I would like to be able to add multiple records via JSON? How could I achieve this? I assumed I might have to create some sort of for loop and push each JSON result to the observable but I was hoping that knockout might have a better way of updating / parsing via JSON?

Heres a copy of what I have achieved so far: http://jsfiddle.net/sparkhill/crSbt/

     function Users(user_id, password) {
    this.user_id = ko.observable();
    this.password = ko.observable();
}

var viewModel = {

    users: ko.observableArray([]),


    addUser: function () {
        this.users.push({

            user_id: "",
            password: ""
        });
    },

    addJSON: function () {


        //Works Fine
        var JSONdataFromServer
        ='{"user_id":"frances","password":"password"}';

        //More than one result - wont map - Would Ideally like to map lots of records at one time
//var JSONdataFromServer ='{"user_id":"frances","password":"password"}, {"user_id":"frances","password":"password"}';

        var dataFromServer = ko.utils.parseJson(JSONdataFromServer);


        this.users.push(dataFromServer);

         //Tried
        //this.users.push(JSON.parse(JSONdataFromServer));


    }

};

viewModel.users();
ko.applyBindings(viewModel);

    </script> 

Update this seems to work but I wonder if their is a more efficient method?

addJSON: function () {

        //Works Fine
        var JSONdataFromServer
        ='[{"user_id":"frances","password":"password"},{"user_id":"timmy","password":"password"}]';

        var results = JSON.parse(JSONdataFromServer);

        var i = results.length;

        for(var i = 0; i < results.length; i++){

            this.users.push(results[i]);
      };   
Gimble answered 1/4, 2012 at 20:21 Comment(0)
L
22

Here are 3 ways you could do this ... found in this fiddle: http://jsfiddle.net/johnpapa/nfnbD/

1) Use the ko.utils.arrayPushAll function 2) use your own logic 3) Write your own function on observableArray

Details ...

1) If you use the ko.utils.arrayPushAll function you will need to call valueHasMutated too, because the array effectively gets overwritten with itself. The observability does not fire off unles you tell it that it changed. Here is how you could do that:

ko.utils.arrayPushAll(this.users(), dataFromServer);
this.users.valueHasMutated();

2) The second option is to write your own loop logic, essentially using the same code as the arrayPushAll function like this.

for (var i = 0, j = dataFromServer.length; i < j; i++)
this.users.push(dataFromServer[i]);

3) Create a function of your own on the observableArray, like this:

ko.observableArray.fn.pushAll = function(valuesToPush) {
        var items = this;
        for (var i = 0, j = valuesToPush.length; i < j; i++){
            items.push(valuesToPush[i]);
        }
        return items;
};

Though this code above will notify every time an item is added. So it might be better to add them all, then notify. This would be more efficient. Like this:

ko.observableArray.fn.pushAll = function(valuesToPush) {
    var underlyingArray = this();
    this.valueWillMutate();
    ko.utils.arrayPushAll(underlyingArray, valuesToPush);
    this.valueHasMutated();
    return this;
};

Then call it like this:

this.users.pushAll(dataFromServer);
Longish answered 1/4, 2012 at 21:18 Comment(4)
keep in mind that you might need to create an instance variable of your model if you want to update your observableArray from somewhere in your page, outside of the actual model itself, e.g.: var myModelInstance = new viewModel(); ko.utils.arrayPushAll(myModelInstance.users(), dataFromServer); `myModelInstance.users.pushallNestling
Is this still the way to go with version 3.1?Polka
I ask the same question as Homer. Is 'pushAll' already in the core of KnockoutJs since version 3.1.Bigod
@Homer, unfortunately, that's still the case with 3.1 .Hip
C
3

You can use the mapping plugin

See http://knockoutjs.com/documentation/plugins-mapping.html

Courtland answered 1/4, 2012 at 21:4 Comment(2)
how does mapping plugin help with the problem ?Osteomyelitis
See section "Advanced usage" (that is available in the linked article). With the plugin you can customize process of the updating/creationCourtland
B
1

I know this is quite an old post but I came across it and just thought I'd show another way to do this in knockout without creating your own pushAll for any future visitors.

You can use a push.apply in knockout on a observable array. This will allow you to push multiple elements from a server and only trigger one notification.

Example in JsFiddle

Edit: The further reading for anyone reading this who wants to know why to use push.apply instead of using push in a loop

Brandeebranden answered 31/1, 2017 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.