Jak wyczyścić / usunąć widoczne wiązania W Knockout.js?
Buduję funkcjonalność na stronie internetowej, którą użytkownik może wykonywać wielokrotnie. Poprzez działanie użytkownika, obiekt / model jest tworzony i stosowany do HTML za pomocą ko.applyBindings ().
HTML związany z danymi jest tworzony za pomocą szablonów jQuery.
Jak na razie dobrze.Kiedy powtórzę ten krok tworząc drugi obiekt / model i wywołuję ko.applyBindings() napotykam dwa problemy:
- znacznik pokazuje poprzedni obiekt / model oraz nowy obiekt/model.
- występuje błąd javascript odnoszący się do jednej z właściwości obiektu/modelu, chociaż nadal jest renderowany w znacznikach.
Aby obejść ten problem, po pierwszym przejściu nazywam jQuery ' s .empty() usuwa szablon HTML, który zawiera wszystkie atrybuty data-bind, tak aby nie znajdował się już w DOM. Gdy użytkownik rozpocznie proces dla drugiego przejścia, HTML związany z danymi jest ponownie dodawany do DOM.
Ale tak jak mówiłem, gdy HTML jest ponownie dodany do DOM i ponownie związany z nowym obiektem / modelem, nadal zawiera dane z pierwszego obiektu / modelu,i nadal dostaję błąd JS, który nie występuje podczas pierwszego przejścia.
Wniosek wydaje się być taki, że Knockout utrzymuje te powiązane właściwości, mimo że znaczniki są usuwane z DOM.
Więc szukam sposobu na usunięcie tych związanych właściwości z Knockoutu; mówienie knockoutowi, że nie ma już obserwowalnego modelu. Czy istnieje jak to zrobić?
EDIT
Podstawowy proces polega na tym, że użytkownik przesyła plik; serwer odpowiada następnie obiektem JSON, HTML związany z danymi jest dodawany do DOM, a następnie model obiektowy JSON jest związany z tym HTML za pomocą
mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);
Gdy użytkownik dokonał pewnych wyborów w modelu, ten sam obiekt jest wysyłany z powrotem do serwera, HTML związany z danymi jest usuwany z DOM, a następnie mam następujący JS
mn.AccountCreationModel = null;
Gdy użytkownik chce to zrobić raz co więcej, wszystkie te kroki są powtarzane.
Obawiam się, że kod jest zbyt 'zaangażowany', aby zrobić demo jsFiddle.
9 answers
Czy próbowałeś wywołać metodę knockout ' s clean node na swoim elemencie DOM, aby pozbyć się obiektów związanych z pamięcią?
var element = $('#elementId')[0];
ko.cleanNode(element);
Następnie ponowne zastosowanie wiązań knockout tylko na tym elemencie z nowymi modelami widoków zaktualizowałoby wiązania widoków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-22 22:00:33
Dla projektu, nad którym pracuję, napisałem prostą funkcję ko.unapplyBindings
, która akceptuje węzeł jQuery i usuń boolean. Najpierw rozłącza wszystkie zdarzenia jQuery, ponieważ metoda ko.cleanNode
o to nie dba. Sprawdziłem wycieki pamięci i wygląda na to, że działa dobrze.
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]);
}
};
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-19 18:30:47
Możesz spróbować użyć wiązania, które oferuje nokaut: http://knockoutjs.com/documentation/with-binding.html Chodzi o to, aby raz użyć apply bindings, a za każdym razem, gdy dane ulegną zmianie, po prostu zaktualizuj swój model.
Powiedzmy, że masz model widoku najwyższego poziomu storeViewModel, Twój koszyk reprezentowany przez cartViewModel, i listę przedmiotów w tym koszyku-powiedzmy cartItemsViewModel.
Powiązałbyś model najwyższego poziomu-model storeViewModel z całą stroną. Wtedy możesz oddziel części swojej strony, które są odpowiedzialne za koszyk lub produkty koszyka.
Przyjmijmy, że cartItemsViewModel ma następującą strukturę:
var actualCartItemsModel = { CartItems: [
{ ItemName: "FirstItem", Price: 12 },
{ ItemName: "SecondItem", Price: 10 }
] }
CartItemsViewModel może być pusty na początku.
Kroki wyglądałyby tak:
-
Definiowanie powiązań w html. Oddziel oprawę 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>
-
Model sklepu pochodzi z twojego serwera (lub jest tworzony w dowolnym innym sposób).
var storeViewModel = ko.mapping.fromJS(modelFromServer)
-
Zdefiniuj puste modele w modelu widoku najwyższego poziomu. Następnie strukturę tego modelu można zaktualizować o rzeczywiste dane.
storeViewModel.cartItemsViewModel = ko.observable(); storeViewModel.cartViewModel = ko.observable();
-
Zwiąż model widoku najwyższego poziomu.
ko.applyBindings(storeViewModel);
-
Gdy obiekt cartItemsViewModel jest dostępny, przypisz go do wcześniej zdefiniowanego elementu zastępczego.
storeViewModel.cartItemsViewModel(actualCartItemsModel);
Jeśli chcesz wyczyścić elementy koszyka:
storeViewModel.cartItemsViewModel(null);
Nokaut zabierze dbałość o html-tzn. pojawi się, gdy model nie jest pusty, a zawartość div (tego Z "Z Wiązaniem") zniknie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-23 07:45:59
Muszę zadzwonić do ko.applyBinding za każdym razem przycisk wyszukiwania kliknij, A filtrowane dane są zwracane z serwera, a w tym przypadku po pracy dla mnie bez użycia ko.cleanNode.
Doświadczyłem, że jeśli zamienimy foreach na template to powinno działać dobrze w przypadku collections / observableArray.
Ten scenariusz może okazać się przydatny.
<ul data-bind="template: { name: 'template', foreach: Events }"></ul>
<script id="template" type="text/html">
<li><span data-bind="text: Name"></span></li>
</script>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-16 06:14:51
Zamiast używać wewnętrznych funkcji KO i radzić sobie z usuwaniem obsługi zdarzeń koca JQuery, znacznie lepszym pomysłem jest użycie wiązań with
LUB template
. Gdy to zrobisz, ko ponownie utworzy tę część DOM i automatycznie zostanie wyczyszczona. Jest to również zalecany sposób, zobacz tutaj: https://stackoverflow.com/a/15069509/207661 .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:29
Myślę, że lepiej będzie zachować Wiązanie przez cały czas i po prostu zaktualizować dane z nim związane. Natknąłem się na ten problem i stwierdziłem, że samo wywołanie przy użyciu metody .resetAll()
na tablicy, w której przechowywałem moje dane, było najskuteczniejszym sposobem na to.
Możesz zacząć od jakiegoś globalnego var, który zawiera dane do renderowania za pomocą ViewModel:
var myLiveData = ko.observableArray();
Zajęło mi trochę czasu, aby uświadomić sobie, że nie mogę po prostu zrobić myLiveData
normalnej tablicy -- ko.oberservableArray
część to było ważne.
Wtedy możesz robić, co chcesz myLiveData
. Na przykład wykonaj $.getJSON
wywołanie:
$.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);
});
Gdy już to zrobisz, możesz jak zwykle zastosować wiązania za pomocą modelu ViewModel:
function MyViewModel() {
var self = this;
self.myData = myLiveData;
};
ko.applyBindings(new MyViewModel());
Następnie w HTML po prostu użyj myData
jak zwykle.
W ten sposób, można po prostu muck z myLiveData z dowolnej funkcji. Na przykład, jeśli chcesz aktualizować co kilka sekund, po prostu zawiń tę linię $.getJSON
w funkcję i wywołaj setInterval
robi się. Nigdy nie będziesz musiał usuwać wiązania, o ile pamiętaj, aby utrzymać linię myLiveData.removeAll();
.
O ile Twoje dane nie są naprawdę ogromne, użytkownicy nie będą nawet w stanie zauważyć czasu pomiędzy zresetowaniem tablicy, a następnie dodaniem najbardziej aktualnych danych z powrotem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-22 05:23:55
Miałem ostatnio problem z wyciekiem pamięci i nie zrobiłbym tego za mnie. Javascript + Nokaut.wyciek pamięci js-jak upewnić się, że obiekt jest niszczony?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:20
Myślałeś o tym:
try {
ko.applyBindings(PersonListViewModel);
}
catch (err) {
console.log(err.message);
}
Wymyśliłem to, ponieważ w nokaut, znalazłem ten kod
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);
}
Więc dla mnie to nie jest naprawdę problem, który jest już związany, to, że błąd nie został złapany i rozwiązany...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-12 15:35:55
Odkryłem, że jeśli model widoku zawiera wiele wiązań div, najlepszym sposobem na wyczyszczenie ko.applyBindings(new someModelView);
jest użycie: ko.cleanNode($("body")[0]);
Pozwala to na dynamiczne wywołanie nowego ko.applyBindings(new someModelView2);
bez obawy, że poprzedni model widoku jest nadal wiązany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-03 15:43:14