34

Is there any option in ko, which pushes multiple elements at same time?

I have two elements which needs to be inserted into a observable array called StatesList, I can not proceed further. How can I add them both.

see Below:

var model1 = jQuery.parseJSON(ko.toJSON(argsToPost));
var model = jQuery.parseJSON(ko.toJSON(self.StateModel));

i need to add both to my ObservableArray

self.StatesList.push(model);
self.StatesList.push(model1);

This is inserting into different records, I want to insert both objects at the same time

1
  • As mentioned in comments to my answer, please try to be a bit clearer - what are you trying to achieve, and how does the actual result of your code differ from what you expect? What do you mean by "at the same time"? Commented May 12, 2014 at 13:35

3 Answers 3

49

We do have ko.utils.arrayPushAll(array, valuesToPush) as a utility function that you can use. It is not available directly off of observableArrays though.

If you add your pushAll to observableArrays, you would want to operate on the underlying array (this() in your case) and then call valueHasMutated() on the observableArray at the end. This will ensure that subscribers to the observableArray are only notified once with the end result rather than with each push.

In KO core, it would need to call valueWillMutate() beforehand as well.

The point was that I would not recommend using the code that you posted, as it will notify on every push, which can have a performance impact if you are pushing many items.

In core, we might do something like:

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

The same discussion happened between John Papa and RP Niemeyer. The link can be found here. Hence, posted only useful tips as an answer here.

Sign up to request clarification or add additional context in comments.

6 Comments

Just to be clear ko.utils.arrayPushAll() will just loop through valuesToPush and call array.Push each time meaning it's inefficient for large lists and sort of defaults the purpose of pushing many items at once.
@Slight this perf test which I have tested on Chrome and FF disagrees jsperf.com/array-prototype-push-apply-vs-concat/76
@LostInComputer Your test involves normal arrays. We're talking about observableArray.Push which notifies subscribers each time it is called. You don't need to run a perf test to know that it is slower than notifying only once.
@Sligh But the code in RJK's answer doesn't use observableArray.Push. It just uses the underlying (normal) array.
@Slight You are right. For 20,000 items, concat is faster in IE11 and Chrome. But if there are only 20 items, loop is faster. 20 items: jsperf.com/array-prototype-push-apply-vs-concat/5
|
31

Try

ko.utils.arrayPushAll(self.StatesList, [model, model1]);

Comments

13

A pushAll function has been discussed on github, see e.g. this issue or this pull request. As far as I gather it has not made it into the main code yet.

However you can easily achieve a push-all like so:

var items = ko.observableArray();

items.push.apply(items, [1, 2, 3, 4]);

as commented by stalniy in the second reference. The downside of this is that knockout will notify the subscribers after every single item pushed.

Alternatively,

function concat(the_list, items_to_concat) {
    the_list.splice.apply(the_list, [the_list().length, 0].concat(items_to_concat));
}

thus making use of the observableArray's splice implementation, as suggested by brianmhunt on the same thread.

BTW: I admit that I did not know this by heart, I simply googled "push many knockout"

2 Comments

your suggestions might be workable, but they are not working in my situation!! ;)
@Aj_sari sorry to hear that. I guess that I did not understand your question right - I thought you were asking for a solution to add multiple elements by a single method call. Can you expand a little on what is "not working in your situation"?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.