开发者

Setting ViewModel data value in afterRender callback function breaks Knockout.js bindings

开发者 https://www.devze.com 2023-04-01 01:16 出处:网络
I have a very complex jquery template that I bind with javascript-based ViewModel data via the knockout.js framework. Actually, I have an observableArray of ViewModel objects within another ViewModel

I have a very complex jquery template that I bind with javascript-based ViewModel data via the knockout.js framework. Actually, I have an observableArray of ViewModel objects within another ViewModel that gets bound to my template.

Within my template, I have several DOM elements that trigger certain events as their values change. For instance, I have a radio button set that changes the binding of a select list (as well as enablement) when a value is selected, which in turn clears the value of a textbox (as well as enablement), by altering various observable properties within my bound ViewModel. These triggers help guide the UX flow for the end-user, as well as ensuring certain v开发者_如何学JAVAalues are saved or cleared as needed. All this works fine.

However...

When I retrieve initial data from my database and populate my ViewModels, then bind the ViewModels to the template, the triggers fire, as they should. However, I do not want the underlying observable values cleared due to the triggers firing. So, what I devised is a way to initially set my ViewModel's IsInitialData observable value to true, which my triggers use to determine whether to clear certain values. However, I want to set these properties to false after my template binding is completed, and before any user interaction is performed.

What made most sense to me was to use the afterRender callback to set the IsInitialData property to false. This way, my triggers would fire normally after the initial data has been bound. My afterRender callback function looks like this:

function resetIsInitialDataAttribute(nodesArray, dataValue) {
    alert(dataValue.IsInitialData()); // Displays 'true'
    dataValue.IsInitialData(false);
    alert(dataValue.IsInitialData()); // Displays 'false'
}

Interesting, I can read the value fine within the above function, even after setting the value.

However...

Once I set the value in the afterRender callback function above, my observable binding seems to break. To test, I have placed a div within my template to serialize my observableArray so I can display all of my ViewModel's values:

<div data-bind="text: ko.toJSON(locationsViewModel.locations)"></div>

If I don't set the IsInitialData property within my afterRender callback, then as I modify my DOM elements that have been bound to my ViewModel's observable properties, the above div instantly displays the modified values. But, if I do set my IsInitialData property in the callback function, the above div no longer displays any changed values in my ViewModel.

Does anyone know why setting my ViewModel's property within the afterRender callback function causes problems? Is there an alternative means for me to set the IsInitialData ViewModel property after my initial database binding is completed? I looked through the jQuery.tmpl documentation for any sort of callback that I can use that takes place after binding my data, but found nothing usable.


Your problem is essentially a version of this issue: https://github.com/SteveSanderson/knockout/issues/133. Also described here.

During afterRender the elements are not actually in the DOM yet. Setting the value of an observable in this code (or in a binding) that was just bound to an element will cause the dependentObservable used in that element's binding to be re-evaluated. It will see that the element is not in the DOM and think that it should dispose of itself.

An easy workaround is to set your value in your afterRender like:

setTimeout(function() { dataValue.IsInitialData(false); }, 0);

This will let the current execution finish at which time your elements will be in the DOM.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号