Knockout.js에서 관찰 가능한 바인딩을 지우거나 제거하는 방법은 무엇입니까?
사용자가 여러 번 수행 할 수있는 웹 페이지에 기능을 구축하고 있습니다. 사용자의 작업을 통해 ko.applyBindings ()를 사용하여 객체 / 모델을 만들고 HTML에 적용합니다.
데이터 바인딩 HTML은 jQuery 템플릿을 통해 생성됩니다.
여태까지는 그런대로 잘됐다.
두 번째 객체 / 모델을 만들어이 단계를 반복하고 ko.applyBindings ()를 호출하면 두 가지 문제가 발생합니다.
- 마크 업에는 이전 객체 / 모델과 새 객체 / 모델이 표시됩니다.
- 객체 / 모델의 속성 중 하나와 관련하여 자바 스크립트 오류가 발생하지만 여전히 마크 업으로 렌더링됩니다.
이 문제를 해결하기 위해 첫 번째 통과 후 jQuery의 .empty ()를 호출하여 모든 데이터 바인딩 속성이 포함 된 템플릿 HTML을 제거하여 더 이상 DOM에 있지 않게합니다. 사용자가 두 번째 단계에 대한 프로세스를 시작하면 데이터 바인딩 된 HTML이 DOM에 다시 추가됩니다.
그러나 내가 말했듯이 HTML이 DOM에 다시 추가되고 새 객체 / 모델에 리 바인드되면 여전히 첫 번째 객체 / 모델의 데이터가 포함되며 여전히 발생하지 않는 JS 오류가 발생합니다. 첫 패스 동안.
결론은 녹아웃이 DOM에서 마크 업을 제거하더라도 이러한 바인딩 된 속성을 유지하는 것으로 보입니다.
그래서 내가 찾고있는 것은 녹아웃에서 이러한 바인딩 된 속성을 제거하는 수단입니다. 더 이상 관찰 가능한 모델이 없다고 녹아웃합니다. 이 방법이 있습니까?
편집하다
기본 프로세스는 사용자가 파일을 업로드하는 것입니다. 그런 다음 서버가 JSON 객체로 응답하고 데이터 바인딩 된 HTML이 DOM에 추가 된 다음 JSON 객체 모델이이 HTML에 바인딩됩니다.
mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);
사용자가 모델을 선택하면 동일한 객체가 서버에 다시 게시되고 데이터 바인딩 된 HTML이 DOM에서 제거되고 다음 JS가 생깁니다.
mn.AccountCreationModel = null;
사용자가이 작업을 한 번 더 원하면이 모든 단계가 반복됩니다.
jsFiddle 데모를 수행하기에는 코드가 너무 '관련되어'있습니다.
메모리에 바운드 된 객체를 처리하기 위해 DOM 요소에서 knockout의 clean node 메소드를 호출하려고 했습니까?
var element = $('#elementId')[0];
ko.cleanNode(element);
그런 다음 새 뷰 모델을 사용하여 해당 요소에만 녹아웃 바인딩을 다시 적용하면 뷰 바인딩이 업데이트됩니다.
내가 작업중 인 프로젝트의 ko.unapplyBindings
경우 jQuery 노드와 부울 제거를 허용하는 간단한 함수를 작성했습니다 . ko.cleanNode
메소드가 처리하지 않으므로 먼저 모든 jQuery 이벤트를 바인드 해제합니다 . 메모리 누수를 테스트했는데 제대로 작동하는 것 같습니다.
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이 제공하는 with 바인딩을 사용해보십시오. http://knockoutjs.com/documentation/with-binding.html 아이디어는 바인딩 적용을 한 번 사용하고 데이터가 변경 될 때마다 모델을 업데이트하는 것입니다.
최상위 뷰 모델 storeViewModel, cartViewModel로 표시되는 카트 및 해당 카트의 항목 목록 (예 : cartItemsViewModel)이 있다고 가정하십시오.
최상위 레벨 모델 인 storeViewModel을 전체 페이지에 바인딩합니다. 그런 다음 장바구니 또는 장바구니 항목을 담당하는 페이지 부분을 분리 할 수 있습니다.
Lets assume that the cartItemsViewModel has the following structure:
var actualCartItemsModel = { CartItems: [
{ ItemName: "FirstItem", Price: 12 },
{ ItemName: "SecondItem", Price: 10 }
] }
The cartItemsViewModel can be empty at the beginning.
The steps would look like this:
Define bindings in html. Separate the cartItemsViewModel binding.
<div data-bind="with: cartItemsViewModel"> <div data-bind="foreach: CartItems"> <span data-bind="text: ItemName"></span> <span data-bind="text: Price"></span> </div> </div>
The store model comes from your server (or is created in any other way).
var storeViewModel = ko.mapping.fromJS(modelFromServer)
Define empty models on your top level view model. Then a structure of that model can be updated with actual data.
storeViewModel.cartItemsViewModel = ko.observable(); storeViewModel.cartViewModel = ko.observable();
Bind the top level view model.
ko.applyBindings(storeViewModel);
When the cartItemsViewModel object is available then assign it to the previously defined placeholder.
storeViewModel.cartItemsViewModel(actualCartItemsModel);
If you would like to clear the cart items: storeViewModel.cartItemsViewModel(null);
Knockout will take care of html - i.e. it will appear when model is not empty and the contents of div (the one with the "with binding") will disappear.
I have to call ko.applyBinding each time search button click, and filtered data is return from server, and in this case following work for me without using ko.cleanNode.
I experienced, if we replace foreach with template then it should work fine in case of collections/observableArray.
You may find this scenario useful.
<ul data-bind="template: { name: 'template', foreach: Events }"></ul>
<script id="template" type="text/html">
<li><span data-bind="text: Name"></span></li>
</script>
Instead of using KO's internal functions and dealing with JQuery's blanket event handler removal, a much better idea is using with
or template
bindings. When you do this, ko re-creates that part of DOM and so it automatically gets cleaned. This is also recommended way, see here: https://stackoverflow.com/a/15069509/207661.
I think it might be better to keep the binding the entire time, and simply update the data associated with it. I ran into this issue, and found that just calling using the .resetAll()
method on the array in which I was keeping my data was the most effective way to do this.
Basically you can start with some global var which contains data to be rendered via the ViewModel:
var myLiveData = ko.observableArray();
It took me a while to realize I couldn't just make myLiveData
a normal array -- the ko.oberservableArray
part was important.
Then you can go ahead and do whatever you want to myLiveData
. For instance, make a $.getJSON
call:
$.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);
});
Once you've done this, you can go ahead and apply bindings using your ViewModel as usual:
function MyViewModel() {
var self = this;
self.myData = myLiveData;
};
ko.applyBindings(new MyViewModel());
Then in the HTML just use myData
as you normally would.
This way, you can just muck with myLiveData from whichever function. For instance, if you want to update every few seconds, just wrap that $.getJSON
line in a function and call setInterval
on it. You'll never need to remove the binding as long as you remember to keep the myLiveData.removeAll();
line in.
Unless your data is really huge, user's won't even be able to notice the time in between resetting the array and then adding the most-current data back in.
I had a memory leak problem recently and ko.cleanNode(element);
wouldn't do it for me -ko.removeNode(element);
did. Javascript + Knockout.js memory leak - How to make sure object is being destroyed?
Have you thought about this:
try {
ko.applyBindings(PersonListViewModel);
}
catch (err) {
console.log(err.message);
}
I came up with this because in Knockout, i found this code
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);
}
So to me its not really an issue that its already bound, its that the error was not caught and dealt with...
I have found that if the view model contains many div bindings the best way to clear the ko.applyBindings(new someModelView);
is to use: ko.cleanNode($("body")[0]);
This allows you to call a new ko.applyBindings(new someModelView2);
dynamically without the worry of the previous view model still being binded.
참고URL : https://stackoverflow.com/questions/10048485/how-to-clear-remove-observable-bindings-in-knockout-js
'programing tip' 카테고리의 다른 글
공백 대신 탭을 삽입하도록 NetBeans를 구성하려면 어떻게해야합니까? (0) | 2020.07.25 |
---|---|
Objective-C로 JSON을 구문 분석하는 방법은 무엇입니까? (0) | 2020.07.25 |
마스터 프로세스의 STDOUT 및 STDERR에 nginx access_log 및 error_log 로그가 있음 (0) | 2020.07.25 |
최고의 프로그래밍 기반 게임 (0) | 2020.07.25 |
자바 스크립트에서 이중 부정 (!!)-목적은 무엇입니까? (0) | 2020.07.25 |