115 votes

Comment faire pour effacer/supprimer des liaisons observables dans Knockout.js ?

Je suis la fonctionnalité du bâtiment sur une page web que l'utilisateur peut effectuer plusieurs fois. Grâce à l'action de l'utilisateur, un objet de modèle est créé et appliqué HTML à l'aide de ko.applyBindings().

Les données liées HTML est créé grâce à jQuery templates.

So far So good.

Quand je répétez cette étape en créant un deuxième objet, de modèle et d'appel ko.applyBindings (), je rencontre deux problèmes:

  1. Le balisage indique l'objet précédent modèle, ainsi que le nouvel objet/modèle.
  2. Une erreur javascript se rapportant à l'une des propriétés de l'objet/modèle, bien qu'il soit encore rendu dans le balisage.

Pour contourner ce problème, après le premier passage que j'appel de jQuery .empty() pour supprimer le basé sur un modèle HTML qui contient toutes les données-lier attributs, de sorte qu'il n'est plus dans les DOM. Lorsque l'utilisateur démarre le processus pour le deuxième passage lié aux données HTML est de nouveau ajouté au DOM.

Mais comme je l'ai dit, quand le HTML est de nouveau ajouté au DOM et re-lié à l'objet nouveau modèle, il comprend toujours des données à partir de la le premier objet/modèle, et j'ai toujours l'erreur JS qui ne se produit pas lors de la première passe.

La conclusion semble être que le knock-out est maintenant sur ces propriétés liées, même si le balisage est retiré de la DOM.

Donc, ce que je suis à la recherche d'un moyen d'enlever ces propriétés liées de knock-out; disant knock-out qu'il n'est plus observable modèle. Est-il un moyen de faire cela?

MODIFIER

Le processus de base est que l'utilisateur télécharge un fichier; ensuite, le serveur répond avec un objet JSON, lié aux données HTML est ajouté au DOM, puis l'objet JSON modèle est lié à cette HTML à l'aide de

mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);

Une fois que l'utilisateur a fait quelques sélections sur le modèle, le même objet est affiché sur le serveur, les données liées HTML est supprimé à partir de là DOM, et j'ai ensuite les suivantes JS

mn.AccountCreationModel = null;

Lorsque l'utilisateur souhaite le faire une fois de plus, toutes ces étapes sont répétées.

J'ai peur que le code est trop "impliqués" pour faire un jsFiddle démo.

174voto

KodeKreachor Points 4808

Avez-vous essayé d'appeler la méthode de nœud en clair de knockout sur votre élément DOM pour vous débarrasser des objets liés en mémoire?

 var element = $('#elementId')[0]; 
ko.cleanNode(element);
 

Ensuite, réappliquer les liaisons défonçables uniquement sur cet élément avec vos nouveaux modèles de vue mettrait à jour votre liaison de vue.

32voto

Michael Berkompas Points 1299

Pour un projet sur lequel je travaille, j'ai écrit une simple fonction ko.unapplyBindings qui accepte un nœud jQuery et le boolean remove. Elle nettoie d’abord tous les événements jQuery en tant que méthode ko.cleanNode ne s’occupe pas de cela. J'ai testé les fuites de mémoire et cela semble bien fonctionner.

 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]);
    }
};
 

12voto

Sylwester Gryzio Points 568

Vous pouvez essayer d'utiliser la liaison avec ko propose: http://knockoutjs.com/documentation/with-binding.html L'idée est d'utiliser appliquer les liaisons de fois, et à chaque fois que vos données de changements, il suffit de mettre à jour votre modèle.

Disons que vous avez un haut niveau modèle de vue storeViewModel, votre panier représenté par cartViewModel, et une liste des éléments dans le panier - dire cartItemsViewModel.

Vous lier le haut niveau du modèle storeViewModel à l'ensemble de la page. Ensuite, vous pouvez séparer les éléments de votre page, qui sont responsables de chariot ou panier articles.

Supposons que le cartItemsViewModel a la structure suivante:

var actualCartItemsModel = { CartItems: [
  { ItemName: "FirstItem", Price: 12 }, 
  { ItemName: "SecondItem", Price: 10 }
] }

Le cartItemsViewModel peut être vide au début.

Les étapes devrait ressembler à ceci:

  1. Définir des liaisons en html. Séparer les cartItemsViewModel de liaison.

      
        <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. Le modèle de magasin vient de votre serveur (ou dans toute autre façon).

    var storeViewModel = ko.mapping.fromJS(modelFromServer)

  3. Définir vide modèles sur votre haut niveau modèle de vue. Ensuite, une structure de ce modèle peut être mis à jour avec données réelles.

      
        storeViewModel.cartItemsViewModel = ko.observable();
        storeViewModel.cartViewModel = ko.observable();
     
    
  4. Lier le haut niveau du modèle de vue.

    ko.applyBindings(storeViewModel);

  5. Lorsque le cartItemsViewModel objet est disponible à l'attribuer à l'défini précédemment réservé.

    storeViewModel.cartItemsViewModel(actualCartItemsModel);

Si vous souhaitez vider le panier items: storeViewModel.cartItemsViewModel(null);

Knock-out va prendre soin de html, c'est à dire qu'il apparaît lorsque le modèle n'est pas vide et le contenu de la div (l'un avec la "avec la liaison") va disparaître.

9voto

aamir sajjad Points 1101

Je dois appeler ko.applyBinding à chaque fois que le bouton de recherche est cliqué et que les données filtrées sont renvoyées par le serveur. Dans ce cas, je travaille sans l'aide de ko.cleanNode.

J'ai expérimenté, si nous remplaçons foreach par template, alors cela devrait fonctionner correctement en cas de collections / observableArray.

Vous pouvez trouver ce scénario utile.

 <ul data-bind="template: { name: 'template', foreach: Events }"></ul>

<script id="template" type="text/html">
    <li><span data-bind="text: Name"></span></li>
</script>
 

6voto

ShitalShah Points 2213

Au lieu d'utiliser les fonctions internes de KO et de s'occuper de la suppression du gestionnaire d'événements global de JQuery, une meilleure idée consiste à utiliser des liaisons with ou template . Lorsque vous faites cela, ko recrée cette partie du DOM et le nettoie automatiquement. Ceci est également recommandé, voir ici: http://stackoverflow.com/a/15069509/207661 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X