KnockoutJs v2.3.0:错误您无法多次将绑定应用于同一元素

时间:2013-07-17 21:42:05

标签: knockout.js

我刚刚升级到2.3.0,现在我收到了错误

  

您不能多次将绑定应用于同一元素。

我没有进入2.2.1。

我从MVC控制器获取部分视图,并在点击href后将其添加到页面中。第二次单击链接以获取局部视图时发生错误。我这样做了很多次。

有没有办法清除它并避免抛出新错误?

这是我的代码:

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

13 个答案:

答案 0 :(得分:96)

在再次使用'applyBindings'之前,您只需要删除绑定。

ko.cleanNode($element[0]);

应该做的伎俩。 HTH。

答案 1 :(得分:22)

可能发生的抛出此异常的事情如下。说你有:

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

现在,当#element1和#element2都不存在时,您将收到错误消息。原因是当找不到#element1和#element2时,Knockout的applyBindings作为根元素回退到document.body。现在它试图在身体上施加两次绑定......

如果你问我,不是Knockout的好回退。我宁愿有一个明确的错误信息,即该元素在DOM中尚不存在。

希望这可以帮助一些人。

答案 2 :(得分:12)

您不应该多次对视图应用绑定。在2.2中,行为未定义,但仍然不受支持。在2.3中,它现在正确显示错误。使用knockout时,目标是将绑定一次应用于页面上的视图,然后对viewmodel上的observable使用更改来更改页面上视图的外观和行为。

答案 3 :(得分:12)

对于上述解决方案来说,有两件事是重要的:

  1. 应用绑定时,需要指定范围(元素)!!

  2. 清除绑定时,必须指定与范围完全相同的元素。

  3. 代码低于

    标记

    <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'));
    

答案 4 :(得分:9)

这个问题有很多很好的答案,但我有一个noobie的答案。

我发现我偶然在两个地方添加了相同的脚本,它试图绑定两次。因此,在您解决一个简单的错误之前,请务必检查此问题。

答案 5 :(得分:5)

我终于通过在绑定处理程序的{ controlsDescendantBindings: true }函数中返回init来解决了我的问题。见this

答案 6 :(得分:4)

如果你反复使用一个元素(在我的情况下是一个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数据转换为可观察数据,这可能会更频繁地发生。

答案 7 :(得分:1)

我发生此错误的原因不同。

我为保存/取消按钮创建了一个模板,我希望它出现在页面的顶部和底部。当我在&lt; script type =&#34; text / html&#34;&gt;内定义模板时,它首先起作用了。 element ....但后来我听说你可以选择用普通的DIV元素创建一个模板。

(这对我来说效果更好,因为我使用的是ASP.NET MVC,并且我的@variableName Razor语法都没有在运行时从脚本元素内部执行。所以通过更改为DIV,我仍然可以使用当页面加载时,MVC Razor引擎在我的KnockoutJs模板中生成HTML。)

在我将模板更改为使用DIV而不是SCRIPT元素后,我的代码看起来像这样......在IE10上运行正常。但是,稍后当我在IE8上测试时,它就抛出了......

&#34;您无法多次将绑定应用于同一元素&#34; 错误.....

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试图多次绑定我的模板DIV,因为它位于applyBindings目标区域内...并且没有使用SCRIPT元素....并且被引用作为模板。

答案 8 :(得分:1)

我在IE7 / IE8中遇到了同样的错误。在包括IE9 / IE10在内的所有其他浏览器中都运行良好。

我发现对我有用的是消除自闭标签。

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

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

答案 9 :(得分:1)

更新答案

现在我们可以使用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)中省略它。

答案 10 :(得分:1)

就我而言,我正在添加一个非现有元素,或者,我正在为可能存在的元素添加绑定,但它的父元素却没有。与此类似:

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

ko.applyBindings(someVM, theDiv);

据我所知,这个错误似乎有点过载,因为它会触发很多不同的错误,这些错误可能会发生在元素上,就像它不存在一样。因此,错误描述可能具有高度欺骗性。它应该可能已经读过:

&#34;未能将绑定绑定到元素。可能的原因包括:多次绑定尝试,元素不存在,元素不在DOM层次结构中,浏览器中的怪癖等等#34;

答案 11 :(得分:0)

我有同样的问题,我解决了。

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

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

setInterval(ShowMessagesList, 10000)

答案 12 :(得分:0)

ko.cleanNode($("#modalPartialView")[0]);
ko.applyBindings(vm, $("#modalPartialView")[0]);

为我工作,但正如其他人指出的那样,cleanNode是内部ko函数,因此可能有更好的方法。