web-dev-qa-db-fra.com

KnockoutJs v2.3.0: Erreur Vous ne pouvez pas appliquer des liaisons plusieurs fois au même élément

Je viens de passer à la version 2.3.0 et le message d'erreur suivant s'affiche: «Vous ne pouvez pas appliquer des liaisons plusieurs fois au même élément. que je n'entrais pas dans 2.2.1.

Je reçois une vue partielle de mon contrôleur MVC et l'ajoute à la page après avoir cliqué sur un href. L'erreur se produit la deuxième fois que je clique sur le lien pour obtenir une vue partielle. Je fais cela plusieurs fois.

Existe-t-il un moyen d’éliminer cela et d’éviter la nouvelle erreur?

Voici mon code:

$.get(url + "GetAssignedCompaniesView?layoutId=" + layoutId + "&noCache=" + new Date().getMilliseconds(), function (result) {
              $("#editAssignedPartial").html($(result));
              showEditAssignedArea(true);
              $(window.document).ready(function () {
                 // error is thrown here
                 ko.applyBindings(self, window.document.getElementById("editAssigned"));
                 $("#layoutId").attr("value", layoutId);
                 updateTypeHiddenElement.attr("value", "companies");
      });
    });
<div id="editAssignedPartial">
</div>

$(document).ready(function () {
  'use strict';
  var vm = new Vm();
  ko.applyBindings(vm, document.getElementById("area1"));
});
69
Aligned

Il vous suffit de supprimer les liaisons avant d'utiliser à nouveau 'applyBindings'.

ko.cleanNode($element[0]);

devrait faire l'affaire. HTH.

92
vprasad

Ce qui peut arriver aussi avec cette exception est la suivante. Disons que vous avez:

ko.applyBindings(myViewModel1, document.getElementById('element1'));
...
ko.applyBindings(myViewModel2, document.getElementById('element2'));

Maintenant, quand # element1 et # element2 n'existent pas, vous obtiendrez l'erreur. La raison en est que applyBindings de Knockout a recours à document.body en tant qu'élément racine lorsque # element1 et # element2 ne sont pas trouvés. Maintenant, il essaie d'appliquer la liaison deux fois sur le corps ...

Pas une belle solution de rechange de Knockout si vous me demandez. Je préférerais avoir un message d'erreur clair indiquant que l'élément n'existe pas (encore) dans le DOM.

J'espère que cela aide certaines personnes.

20
Almer

Vous ne devez jamais appliquer de liaisons plus d'une fois à une vue. Dans la version 2.2, le comportement n'était pas défini, mais toujours non pris en charge. En 2.3, il affiche maintenant correctement une erreur. Lors de l'utilisation de la suppression, l'objectif consiste à appliquer des liaisons une fois sur votre ou vos vues sur la page, puis à utiliser les modifications apportées aux observables sur votre modèle de vue pour modifier l'apparence et le comportement de vos vues sur votre page. 

12
x0n

Deux choses sont importantes pour que les solutions ci-dessus fonctionnent:

  1. Lors de l'application de liaisons, vous devez spécifier scope (element) !!

  2. Lorsque vous effacez des liaisons, vous devez spécifier exactement le même élément que celui utilisé pour la portée.

Le code est ci-dessous

Markup

<div id="elt1" data-bind="with: data">
    <input type="text" data-bind="value: text1" >
</form>

Vue obligatoire

var myViewModel = {
  "data" : {
    "text1" : "bla bla"
  }
}:

Javascript

ko.applyBindings(myViewModel, document.getElementById('elt1'));

Reliures claires

ko.cleanNode(document.getElementById('elt1'));
12
Mitja Gustin

Il y a beaucoup de bonnes réponses à ce problème mais j'ai une réponse noobie.

J'ai constaté que j'avais accidentellement ajouté le même script à deux endroits et qu'il essayait de se lier deux fois. Donc, avant de vous tirer les cheveux d'une simple erreur, vérifiez ce problème. 

9
Pete

J'ai finalement résolu le mien en renvoyant { controlsDescendantBindings: true } dans la fonction init du gestionnaire de liaisons. Voir this

5
Martin Lottering

Si vous réutilisez un élément à plusieurs reprises (une boîte de dialogue modale d'amorçage dans mon cas), appeler ko.applyBindings(el) à plusieurs reprises entraînera ce problème.

Au lieu de cela, faites-le une fois comme ceci:

if (!applied) {
    ko.applyBindings(el);
    applied = true;
}

Ou comme ceci:

var apply = function (viewModel, containerElement) {
    ko.applyBindings(viewModel, containerElement);
    apply = function() {}; // only allow this function to be called once.
}

PS: Cela peut vous arriver plus souvent si vous utilisez le plug-in de mappage et convertissez vos données JSON en observables.

4
Jess

Réponse mise à jour

Maintenant que nous pouvons utiliser dataFor() pour vérifier si la liaison a été appliquée, je préférerais vérifier la liaison des données plutôt que cleanNode() et applyBindings().

Comme ça:

var koNode = document.getElementById('formEdit');
var hasDataBinding = !!ko.dataFor(koNode);
console.log('has data binding', hasDataBinding);
if (!hasDataBinding) { ko.applyBindings(vm, koNode);}

Réponse originale.

Beaucoup de réponses déjà!

Tout d'abord, supposons qu'il soit assez courant de devoir relier plusieurs fois la liaison dans une page. Dis, j'ai un formulaire dans le modal Bootstrap, qui sera chargé encore et encore. La plupart des entrées de formulaire ont une liaison bidirectionnelle.

Je choisis généralement la voie la plus facile: effacer la reliure à chaque fois avant la reliure.

var koNode = document.getElementById('formEdit');
ko.cleanNode(koNode);
ko.applyBindings(vm, koNode);

Assurez-vous simplement qu'ici koNode est requis, car ko.cleanNode() requiert un élément node, même si nous pouvons l'omettre dans ko.applyBinding(vm).

1
Blaise

Dans mon cas, j'ajoutais à un élément inexistant, ou j'ajoutais des liaisons à un élément qui existe peut-être, mais pas à l'élément parent. Semblable à ceci:

var segDiv =  $("#segments"); //did not exist, wrong id
var theDiv = segDiv.html("<div></div>");

ko.applyBindings(someVM, theDiv);

Autant que je sache, cette erreur semble un peu surchargée dans le sens où elle se déclenchera sur de nombreuses erreurs différentes pouvant survenir avec l'élément, comme s'il n'existait pas. En tant que telle, la description de l'erreur peut être très trompeuse. Il aurait probablement dû lire:

"Échec de la liaison des liaisons avec l'élément. Les raisons possibles sont les suivantes: tentatives de liaison multiples, élément inexistant, élément non défini dans la hiérarchie DOM, bizarreries dans les navigateurs, etc."

1
Neoraptor

J'ai eu cette erreur se produire pour une raison différente.

J'ai créé un modèle pour les boutons Enregistrer/Annuler que je voulais voir apparaître en haut et en bas de la page. Cela a fonctionné au début lorsque mon modèle a été défini dans un élément <script type = "text/html"> ... mais j'ai entendu dire que vous pouviez éventuellement créer un modèle à partir d'un élément DIV ordinaire. 

(Cela fonctionnait mieux pour moi puisque j'utilisais ASP.NET MVC et qu'aucune de mes syntaxes @variableName Razor n'était exécutée à l'exécution à partir de l'intérieur de l'élément de script. Donc, en passant à DIV, je pouvais toujours avoir le moteur MVC Razor générer du HTML dans mon modèle KnockoutJs lors du chargement de la page.)

Après avoir changé mon modèle pour utiliser une DIV au lieu d'un élément SCRIPT, mon code ressemblait à ceci .... ce qui fonctionnait bien sous IE10. Cependant, plus tard lorsque je l’ai testé sur IE8 , il a jeté ça ....

"Vous ne pouvez pas appliquer plusieurs fois des liaisons au même élément" error .....

HTML

<div id="mainKnockoutDiv" class="measurementsDivContents hourlyMeasurements">

  <div id="saveButtons_template" style="display: none;">
    ... my template content here ...
  </div>

  <!--ko template: { name: 'saveButtons_template' } -->
  <!--/ko-->

  Some_HTML_content_here....

  <!--ko template: { name: 'saveButtons_template' } -->
  <!--/ko-->

</div>

JavaScript

ko.applyBindings(viewModel, document.getElementById('mainKnockoutDiv'));

LA SOLUTION :

Tout ce que j'avais à faire, c'était de déplacer mon saveButtons_template DIV vers le bas, de sorte qu'il se trouvait en dehors de mainKnockoutDiv. Cela a résolu le problème pour moi. 

Je suppose que KnockoutJs a essayé de lier plusieurs fois mon modèle DIV, car il se trouvait dans la zone cible applyBindings ... et n'utilisait pas l'élément SCRIPT .... et était référencé en tant que modèle.

1
ClearCloud8

Je recevais la même erreur dans IE7/IE8. Fonctionne bien dans tous les autres navigateurs, y compris IE9/IE10.

Ce que j'ai trouvé a fonctionné pour moi a été d'éliminer les étiquettes à fermeture automatique. 

Mal

<div>
    <span data-bind="text: name"/>
</div>

Bien

<div>
    <span data-bind="text: name"></span>
</div>
1
Two Seeds
ko.cleanNode($("#modalPartialView")[0]);
ko.applyBindings(vm, $("#modalPartialView")[0]);

cela fonctionne pour moi, mais comme d’autres le remarquent, la cleanNode est une fonction interne ko;.

0
Muflix

j'ai eu le même problème et je l'ai résolu.

var vm = new MessagesViewModel()
ko.applyBindings(vm)

function ShowMessagesList() {
   vm.getData("MyParams")
}

setInterval(ShowMessagesList, 10000)
0
javad hemati