如何清除/删除Knockout.js中的可观察的绑定?
我正在将function构build到用户可以多次执行的网页上。 通过用户的操作,使用ko.applyBindings()创build对象/模型并将其应用于HTML。
数据绑定的HTML是通过jQuery模板创build的。
到现在为止还挺好。
当我通过创build第二个对象/模型重复这一步,并调用ko.applyBindings()我遇到两个问题:
- 标记显示了以前的对象/模型以及新的对象/模型。
- 尽pipe仍然在标记中呈现,但是与对象/模型中的其中一个属性有关的javascript错误。
为了解决这个问题,在第一次传递之后,我调用jQuery的.empty()来移除包含所有数据绑定属性的模板化HTML,以使其不再位于DOM中。 当用户启动第二遍的过程时,数据绑定的HTML被重新添加到DOM。
但正如我所说,当HTML被重新添加到DOM,并重新绑定到新的对象/模型,它仍然包括来自第一个对象/模型的数据,我仍然得到JS错误不会发生在第一次通过。
结论似乎是Knockout坚持这些绑定的属性,即使标记从DOM中删除。
所以我正在寻找的是一种从Knockout中去除这些绑定属性的方法; 告诉淘汰赛,不再有可观察的模型。 有没有办法做到这一点?
编辑
基本过程是用户上传文件; 服务器然后响应一个JSON对象,数据绑定的HTML被添加到DOM,然后JSON对象模型绑定到这个HTML使用
mn.AccountCreationModel = new AccountViewModel(jsonData.Account); ko.applyBindings(mn.AccountCreationModel);
一旦用户在模型上做了一些select,同一个对象被发回到服务器,数据绑定的HTML被从DOM中删除,然后我有以下的JS
mn.AccountCreationModel = null;
当用户希望再次这样做时,重复所有这些步骤。
恐怕代码太“参与”做一个jsFiddle演示。
你有没有尝试在你的DOM元素上调用knockout的clean节点方法来处理内存绑定对象?
var element = $('#elementId')[0]; ko.cleanNode(element);
然后再使用你的新视图模型在这个元素上再次应用knockout绑定会更新你的视图绑定。
对于我正在开发的项目,我编写了一个简单的ko.unapplyBindings
函数,它接受一个jQuery节点和remove布尔值。 它首先解除所有的jQuery事件,因为ko.cleanNode
方法不会处理这个问题。 我已经testing了内存泄漏,它似乎工作得很好。
ko.unapplyBindings = function ($node, remove) { // unbind events $node.find("*").each(function () { $(this).unbind(); }); // Remove KO subscriptions and references if (remove) { ko.removeNode($node[0]); } else { ko.cleanNode($node[0]); } };
你可以尝试使用knockout提供的绑定: http : //knockoutjs.com/documentation/with-binding.html这个想法是使用apply绑定一次,只要你的数据发生变化,就更新你的模型。
比方说,你有一个顶级视图模型storeViewModel,cartViewModel代表您的购物车,并在该购物车中的项目列表 – 说cartItemsViewModel。
您将绑定顶层模型 – storeViewModel到整个页面。 然后,您可以分离页面中负责购物车或购物车项目的部分。
让我们假设cartItemsViewModel具有以下结构:
var actualCartItemsModel = { CartItems: [ { ItemName: "FirstItem", Price: 12 }, { ItemName: "SecondItem", Price: 10 } ] }
cartItemsViewModel在开始时可以是空的。
步骤如下所示:
-
在html中定义绑定。 分离cartItemsViewModel绑定。
<div data-bind="with: cartItemsViewModel"> <div data-bind="foreach: CartItems"> <span data-bind="text: ItemName"></span> <span data-bind="text: Price"></span> </div> </div>
<div data-bind="with: cartItemsViewModel"> <div data-bind="foreach: CartItems"> <span data-bind="text: ItemName"></span> <span data-bind="text: Price"></span> </div> </div>
-
商店模型来自您的服务器(或以任何其他方式创build)。
var storeViewModel = ko.mapping.fromJS(modelFromServer)
-
在顶级视图模型上定义空模型。 然后可以用实际的数据更新该模型的结构。
storeViewModel.cartItemsViewModel = ko.observable(); storeViewModel.cartViewModel = ko.observable();
storeViewModel.cartItemsViewModel = ko.observable(); storeViewModel.cartViewModel = ko.observable();
-
绑定顶层视图模型。
ko.applyBindings(storeViewModel);
-
当cartItemsViewModel对象可用时,将其分配给以前定义的占位符。
storeViewModel.cartItemsViewModel(actualCartItemsModel);
如果您想清除购物车商品: storeViewModel.cartItemsViewModel(null);
淘汰赛将照顾的HTML – 即它会出现时,模型不是空的div的内容(与“绑定”的那个将消失。
我必须调用ko.applyBinding每次searchbutton点击,并过滤的数据是从服务器返回,在这种情况下,下面的工作,我没有使用ko.cleanNode。
我经历过,如果我们用模板replaceforeach,那么它应该在集合/ observableArray的情况下工作正常。
你可能会发现这个场景很有用。
<ul data-bind="template: { name: 'template', foreach: Events }"></ul> <script id="template" type="text/html"> <li><span data-bind="text: Name"></span></li> </script>
除了使用KO的内部函数和处理JQuery的一揽子事件处理程序删除,更好的办法是使用with
或template
绑定。 当你这样做时,ko重新创buildDOM的那部分,所以它会自动清理。 这也是推荐的方式,请看这里: https : //stackoverflow.com/a/15069509/207661 。
我认为保持整个绑定可能会更好,只需更新与之关联的数据即可。 我遇到了这个问题,并发现只使用数组中的.resetAll()
方法来调用我的数据是最有效的方法。
基本上,你可以从一些全局var开始,它包含要通过ViewModel呈现的数据:
var myLiveData = ko.observableArray();
我花了一段时间才意识到我不能让myLiveData
成为一个正常的数组 – ko.oberservableArray
部分很重要。
然后你可以继续做你想要的任何我的myLiveData
。 例如,做一个$.getJSON
调用:
$.getJSON("http://foo.bar/data.json?callback=?", function(data) { myLiveData.removeAll(); /* parse the JSON data however you want, get it into myLiveData, as below */ myLiveData.push(data[0].foo); myLiveData.push(data[4].bar); });
一旦你这样做了,你可以像往常一样继续使用ViewModel来应用绑定:
function MyViewModel() { var self = this; self.myData = myLiveData; }; ko.applyBindings(new MyViewModel());
然后在HTML中, myData
使用myData
。
这样,你可以从任何函数中使用myLiveData。 例如,如果您想每隔几秒更新一次,只需将该$.getJSON
行包装在函数中,然后调用setInterval
。 只要您记得保留myLiveData.removeAll();
您将永远不需要删除绑定myLiveData.removeAll();
在线。
除非您的数据真的很大,否则用户甚至无法注意到在重置数组和重新添加最新数据之间的时间。
我最近有一个内存泄漏问题,并且ko.cleanNode(element);
不会为我做 – ko.removeNode(element);
没有。 JavaScript + Knockout.js内存泄漏 – 如何确保对象被销毁?
我发现,如果视图模型包含许多div绑定清除ko.applyBindings(new someModelView);
的最佳方法ko.applyBindings(new someModelView);
是使用: ko.cleanNode($("body")[0]);
这允许你调用一个新的ko.applyBindings(new someModelView2);
dynamic而不必担心以前的视图模型仍然绑定。
你有没有想过这个:
try { ko.applyBindings(PersonListViewModel); } catch (err) { console.log(err.message); }
我想出了这个,因为在Knockout中,我find了这个代码
var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey); if (!sourceBindings) { if (alreadyBound) { throw Error("You cannot apply bindings multiple times to the same element."); } ko.utils.domData.set(node, boundElementDomDataKey, true); }
所以对我来说,它不是一个已经存在的问题,它的错误没有被发现和处理。