web-dev-qa-db-ja.com

KnockoutJs v2.3.0:エラー同じ要素に複数回バインディングを適用することはできません

2.3.0にアップグレードしたところ、エラーが発生しました

同じ要素にバインディングを複数回適用することはできません。

2.2.1で取得できなかったこと。

MVCコントローラーから部分的なビューを取得し、hrefをクリックした後にページに追加しています。このエラーは、2回目にリンクをクリックして部分的なビューを取得したときに発生します。これを複数回行っています。

これをクリアして、スローされる新しいエラーを回避する方法はありますか?

私のコードは次のとおりです。

$.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"));
});
72
Aligned

「applyBindings」を再度使用する前に、バインディングを削除する必要があります。

ko.cleanNode($element[0]);

トリックを行う必要があります。 HTH。

96
vprasad

この例外をスローする同様に発生する可能性のあるものは次のとおりです。あなたが持っていると言う:

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

これで、#element1と#element2の両方が存在しない場合、エラーが発生します。その理由は、#element1と#element2が見つからない場合、KnockoutのapplyBindingsがdocument.bodyをルート要素としてフォールバックするためです。これで、ボディに2回バインディングを適用しようとします...

あなたが私に尋ねると、ノックアウトの素晴らしいフォールバックではありません。要素がDOMに存在しない(まだ)という明確なエラーメッセージが欲しいです。

これが一部の人々に役立つことを願っています。

23
Almer

上記のソリューションが機能するには、2つのことが重要です。

  1. バインディングを適用するときは、スコープ(要素)を指定する必要があります!!

  2. バインディングをクリアするときは、スコープに使用されるものとまったく同じ要素を指定する必要があります。

コードは以下です

Markup

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

バインドビュー

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

Javascript

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

明確なバインディング

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

ビューにバインディングを複数回適用しないでください。 2.2では、動作は未定義でしたが、まだサポートされていません。 2.3では、エラーが正しく表示されるようになりました。ノックアウトを使用する場合の目標は、ページ上のビューにバインディングを一度適用し、ビューモデル上のオブザーバブルへの変更を使用して、ページ上のビューの外観と動作を変更することです。

12
x0n

この問題には多くの素晴らしい答えがありますが、私はnoobie answer。を持っています

同じスクリプトを誤って2か所に追加し、2回バインドしようとしたことがわかりました。簡単なミスで髪を引き抜く前に、この問題を確認してください。

9
Pete

バインディングハンドラーのinit関数で{ controlsDescendantBindings: true }を返すことでようやく解決しました。 this を参照してください

5

要素を何度も再利用する場合(私の場合はbootstrapモーダルダイアログ)、ko.applyBindings(el)を複数回呼び出すとこの問題が発生します。

代わりに、次のように一度だけ実行してください。

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

またはこのように:

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

PS:これは、マッピングプラグインを使用してJSONデータをオブザーバブルに変換する場合に頻繁に発生する可能性があります。

4
Jess

更新された回答

dataFor()を使用してバインディングが適用されているかどうかを確認できるようになったので、cleanNode()およびapplyBindings()ではなく、データバインディングを確認することをお勧めします。

このような:

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

元の回答。

すでにたくさんの答え!

まず、ページ内で複数回バインディングを行う必要があることはかなり一般的だとしましょう。たとえば、Bootstrapモーダル内にフォームがあり、これは何度もロードされます。フォーム入力の多くには双方向のバインディングがあります。

私は通常、簡単なルートを取ります。バインディングの前に毎回バインディングをクリアします。

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

ここでkoNodeが必須であることを確認してください。ko.cleanNode()では省略できますが、ko.applyBinding(vm)にはノード要素が必要です。

1
Blaise

私の場合、存在しない要素に追加していたか、存在する可能性のある要素にバインディングを追加していましたが、親ではありませんでした。これに似ています:

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

ko.applyBindings(someVM, theDiv);

私が知る限り、このエラーは、存在しないなど、要素で発生する可能性のある多くの異なるエラーで発生するという意味で、少し過負荷になっているようです。そのため、エラーの説明は非常に誤解を招く可能性があります。おそらく次のようになっているはずです。

「バインドを要素にバインドできません。考えられる理由には、複数のバインドの試行、存在しない要素、DOM階層にない要素、ブラウザの癖などがあります」

1
Neoraptor

別の理由でこのエラーが発生しました。

ページの上下に表示する保存/キャンセルボタン用のテンプレートを作成しました。テンプレートが<script type = "text/html">要素内で定義されていたときに最初は機能しましたが、その後、通常のDIV要素からオプションでテンプレートを作成できると聞きました。

(これは、ASP.NET MVCを使用しており、@ variableName Razor構文のいずれもスクリプト要素の内部から実行時に実行されていなかったので、私にとってはうまくいきました。ページの読み込み時にKnockoutJsテンプレート内でHTMLを生成します。)

SCRIPT要素の代わりにDIVを使用するようにテンプレートを変更した後、コードは次のようになりました。IE...しかし、後でIE8でテストしたとき、それは投げた....

「同じ要素に複数回バインディングを適用することはできません」 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'));

ソリューション

私がしなければならなかったことは、saveButtons_template DIVを下に移動して、mainKnockoutDivの外側に置くことだけでした。これで問題は解決しました。

KnockoutJsは、applyBindingsターゲットエリア内にあり、SCRIPT要素を使用していないため、テンプレートDIVを複数回バインドしようとしていたと思われます。..テンプレートとして参照されていました。

1
ClearCloud8

IE7/IE8でも同じエラーが発生していました。 IE9/IE10を含む他のすべてのブラウザーで正常に動作しました。

私が見つけたのは、自己終了タグを削除することでした。

悪い

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

良い

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

私のために動作しますが、他の人が注意するように、cleanNodeは内部ko関数なので、おそらくより良い方法があります。

0
Muflix

私は同じ問題を抱えていて、それを解決しました。

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

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

setInterval(ShowMessagesList, 10000)
0
javad hemati