在 afterRender 回调函数中设置 ViewModel 数据值会破坏 Knockout.js 绑定
我有一个非常复杂的 jquery 模板,我通过 knockout.js 框架与基于 javascript 的 ViewModel
数据绑定。实际上,我在另一个绑定到我的模板的 ViewModel
中有一个由 ViewModel
对象组成的 observableArray
。
在我的模板中,我有几个 DOM 元素,它们在值发生变化时触发某些事件。例如,我有一个单选按钮集,当选择一个值时,它会更改选择列表(以及启用)的绑定,从而通过更改各种可观察的属性来清除文本框的值(以及启用)在我绑定的 ViewModel 中。这些触发器有助于指导最终用户的用户体验流程,并确保根据需要保存或清除某些值。这一切都运行良好。
但是...
当我从数据库检索初始数据并填充我的 ViewModels,然后将 ViewModels 绑定到模板时,触发器将按其应有的方式触发。但是,我不希望由于触发器触发而清除基础可观察值。因此,我设计了一种将我的 ViewModel
的 IsInitialData
可观察值初始设置为 true
的方法,我的触发器使用它来确定是否清除某些值。但是,我想在模板绑定完成后、执行任何用户交互之前将这些属性设置为 false
。
对我来说最有意义的是使用 afterRender
回调将 IsInitialData
属性设置为 false
。这样,我的触发器将在初始数据绑定后正常触发。我的 afterRender
回调函数如下所示:
function resetIsInitialDataAttribute(nodesArray, dataValue) {
alert(dataValue.IsInitialData()); // Displays 'true'
dataValue.IsInitialData(false);
alert(dataValue.IsInitialData()); // Displays 'false'
}
有趣的是,即使在设置值之后,我也可以在上述函数中很好地读取该值。
但是...
一旦我在上面的 afterRender 回调函数中设置了值,我的可观察绑定似乎就会中断。为了进行测试,我在模板中放置了一个 div 来序列化我的 observableArray
,以便我可以显示所有 ViewModel
的值:
<div data-bind="text: ko.toJSON(locationsViewModel.locations)"></div>
如果我不设置 >IsInitialData
属性在我的 afterRender
回调中,然后当我修改已绑定到我的 ViewModel
可观察属性的 DOM 元素时,上面的 div 立即显示修改后的值。但是,如果我在回调函数中设置了 IsInitialData
属性,则上面的 div 不再在我的 ViewModel
中显示任何更改的值。
有谁知道为什么在 afterRender
回调函数中设置我的 ViewModel
属性会导致问题?在初始数据库绑定完成后,是否有其他方法可以设置 IsInitialData
ViewModel
属性?我查看了 jQuery.tmpl 文档,了解绑定数据后可以使用的任何类型的回调,但发现没有任何可用的内容。
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 values 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的问题本质上是此问题的一个版本: https://github.com/SteveSanderson/knockout/问题/133。还在此处进行了描述。
在
afterRender
期间,元素实际上并不在 DOM 中。在此代码(或绑定)中设置刚刚绑定到元素的 observable 的值将导致重新评估该元素绑定中使用的 dependentObservable。它会发现该元素不在 DOM 中,并认为它应该自行处理。一个简单的解决方法是在
afterRender
中设置您的值,如下所示:这将使当前执行完成,此时您的元素将位于 DOM 中。
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:This will let the current execution finish at which time your elements will be in the DOM.