1 person found this helpful
I have two suggestions:
#1: Don't replace the array within the observableArray. Yes, sometimes that works. Sometimes it doesn't. It seems to depend on the implementation of the underlying component and how it binds to the observable and the observable's data. Instead, populate the observableArray itself when the promise is fulfilled. My favorite way to do this looks something like this:
ko.utils.arrayPushAll(self.chemicals(), c); self.chemicals.valueHasMutated();
If you need to manipulate the data returned by the promise, then assign the observable array to a temp variable and then push into the array OUTSIDE of the observable construct. Then invoke valueHasMutated. This will keep ko from attempting to update the DOM on every push.
You can see an example of something like this here: Multi select does not work when binding options from REST call. This example uses window.setTimeout to simulate the asynchronous nature of Ajax, causing the UI to render before the data is ready. jsFiddle here: https://jsfiddle.net/jmarion/8079eeoc/.
#2: Use the if binding to keep the chemicals array out of the DOM until the promise resolves and you have real data. Basically, you wrap the DOM that uses the chemicals binding in an if binding and then ko won't know about/process the binding until AFTER the data is ready.
I like option #1 because I like to make as much of the UI visible/available as soon as possible. But if that doesn't work, then I fall back on option 2.
The solution 2 is working! Let me try solution 1! Thank you very much Jim!
1 person found this helpful
Thank you for your help!
I'm trying the first solution and I have some questions:
When you say "push into the array OUTSIDE of the observable construct", what do you mean by that? Do you mean I do push outside Promise? Or I do ko.utils.arrayPushAll(self.chemicals(), c) in the Promise?
Thank you again for your kind help! I really appreciate it!
Great question. Do as you said:
do ko.utils.arrayPushAll(self.chemicals(), c) in the Promise
If your Ajax response data matches exactly what your view expects, then you are all set. I didn't want to assume that was the case. If you have to manipulate the data first (using forEach or map or something), that is when my extra piece of advice matters. When pushing data into an observableArray item-by-item, you have two options: use the observableArray methods or work with the raw array directly. If you are only updating one row, then using the observableArray array methods is best because that keeps the view and model in sync. In this case, however, you are pushing all of the data into the array at once. In this case, for performance reasons, "the experts" recommend that you work with the raw array directly. When done, you can trigger the view by invoking valueHasMutated.