Update Knockout.js Observable from JSON

2019-01-22 21:15发布

问题:

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]);
      };   

回答1:

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);


回答2:

You can use the mapping plugin

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



回答3:

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