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:

  1. znacznik pokazuje poprzedni obiekt / model oraz nowy obiekt/model.
  2. 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.

Author: awj, 2012-04-06

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.

 162
Author: KodeKreachor,
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]);
    }
};
 30
Author: Michael Berkompas,
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:

  1. 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>
      
    
  2. Model sklepu pochodzi z twojego serwera (lub jest tworzony w dowolnym innym sposób).

    var storeViewModel = ko.mapping.fromJS(modelFromServer)

  3. 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();
     
    
  4. Zwiąż model widoku najwyższego poziomu.

    ko.applyBindings(storeViewModel);

  5. 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.

 12
Author: Sylwester Gryzio,
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>
 9
Author: aamir sajjad,
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 .

 6
Author: ShitalShah,
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.

 4
Author: Zac,
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?

 2
Author: Matas Vaitkevicius,
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...

 1
Author: ozzy432836,
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.

 0
Author: Derrick Hampton,
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