Knockout.js动态生成HTML无法获取更新

时间:2016-03-11 18:04:03

标签: javascript html ajax knockout.js

我有一个相当复杂的系统在后台工作,会尝试给出最简洁和最简短的例子:

我有一个PHP / HTML页面,它会激活对服务器的Ajax调用并返回响应XML。基于XML,javascript动态创建了一堆DOM元素。 XML还包含我映射到主页上存在的挖空视图模型的数据。

然而,元素没有得到更新,或者更确切地说,knockout.js根本没有与它们进行交互(我将假设ko.applyBinding(模型)应该受到责备。

这是我需要的:  1.加载一个包含knockout.js和视图模型对象的PHP页面。  2.发送一个AJAX请求,该请求返回新数据以更新模型以及添加到页面中的新HTML DOM元素。  3.让knockout.js跟踪这些新元素中的数据信息。

我看到的问题是ko.applyBinding(模型)在DOM元素存在于DOM之前被触发,因此它们永远不会受到约束,但是根本没有办法知道将添加哪些元素以及什么数据将从服务器中提取,并且必须保持动态。

我已经确定如果我可以重新应用绑定它会工作(我认为)但是尝试这样做会产生错误。我在其他几篇文章中读到,没有办法重新应用整个文档的绑定,但必须为每个元素单独完成,但是这些元素必须是DOM中的兄弟,而不是为我工作,因为他们需要嵌套。

关于解决方案的任何想法?

编辑:制作一个JSFiddle示例,但由于我不能将knockout-mapping.js包含在其中,因此无效,因此我准备了.HTML文档并添加了所需的库( knockout.js和knockout-mapping.js),将它们全部链接起来并上传here这是一个.rar文件,包含所有设置和库。

EDIT2: 下面还可以看到所需内容的简短预览:

var ViewModel = {
  buttonOneText: ko.observable("Button 1")
}

ko.applyBindings(ViewModel);

// IMAGINARY AJAX HAPPENS
// when this happens I need to add another button into the frameDiv and add it's data to the model.

document.getElementById("frameDiv").innerHTML += '<button type="button" data-bind="text: buttonTwoText"></button>'
ViewModel.buttonTwoText = "Button 2";

ko.applyBindings(ViewModel, document.getElementById("frameDiv"));

//				So far this works, and it is great!
//				If you comment out the rest of the JS code it will work perfectly
//				problem comes when you attempt to add a thrid element, because
//				even though "frameDiv" has no bind-data, it doesn't let you run it
//				again on that div.

document.getElementById("frameDiv").innerHTML += '<button type="button" data-bind="text: buttonThreeText"></button>'
ViewModel.buttonThreeText = "Button 3";

ko.applyBindings(ViewModel, document.getElementById("frameDiv"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="frameDiv">
  <button type="button" data-bind="text: buttonOneText"></button>

  <!-- The following element will be added VIA Javascript code -->
  <!--<button type="button" data-bind="text: buttonTwoText"></button>-->
</div>

1 个答案:

答案 0 :(得分:1)

您可以为ko.applyBindings提供第二个参数,指定要应用绑定的顶级节点。您可以在您创建的任何节点上调用此方法,只要您没有在其下放置已绑定的节点。

这是一个带有例程的示例脚本,该例程创建一个新的DOM节点,插入它并对其应用绑定。单击按钮执行例程。

parser = new DOMParser();
foo = 1;

vm = {
  makeNode: function() {
    var el = parser.parseFromString('<div data-bind="text:' + foo + '"></div>', "text/xml").childNodes[0];
    ++foo;
    document.getElementById('foo').appendChild(el);
    ko.applyBindings(vm, el);
  }
};

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="foo">
</div>
<button data-bind="click: makeNode">Add node</button>