RequireJS with Knockout - 多次应用绑定

时间:2016-01-12 09:44:39

标签: javascript knockout.js requirejs

我试图使用RequireJS简化KnockoutJS组件的开发。问题是,它说我多次将绑定应用于同一个元素。

需要-config.js

var require = {
  baseUrl: ".",
  paths: {
    "bootstrap": "bower_components/bootstrap/dist/js/bootstrap.min",
    "jquery": "bower_components/jquery/dist/jquery.min",
    "knockout": "bower_components/knockout/dist/knockout",
    "text": "bower_components/text/text"
  },
  shim:{
    "bootstrap": {deps: ["jquery"]}
  }
}

main.js

define(["jquery", "knockout", "bootstrap"], function($, ko){
    ko.components.register("sel-text", { require: "components/selecttextarea/selecttextarea" });
    ko.applyBindings({});
});

selecttextarea.js - (我创建的组件)

define(["knockout", "text!./selecttextarea.html"], function(ko, template){
  function SelTextareaViewModel(params){
     var self = this;
     self.items = ko.observableArray(params.items);
     self.caption = ko.observable();
  }

  return{ viewModel: SelTextareaViewModel, template: template};
});

尝试使用组件

的index.html

  <div class="row" id="asd">
       <pre data-bind="text: ko.toJSON($root.selectItems)"></pre>
       <sel-text params="items: $root.selectItems"></sel-text>
  </div>

      ...

<script>
require(['js/page1']);
</script>

page1.js

require(["jquery", "knockout"], function($, ko){

  var data = [{"val": 0, "text": "Hello"}, {"val": 1, "text": "Bloody"}, {"val": 2, "text": "World"}];
    function SimpleViewModel(d){
      var self = this;
      self.selectItems = ko.observableArray(d);
    }
    ko.applyBindings(new SimpleViewModel(data), $('#asd')[0]);
});

如果我删除<pre>标记,则表示不会显示错误,就像它尝试将绑定应用于$('#asd')[0]中的每个元素一样。

我感到困惑,有什么建议吗?

更新

从评论中可以看出,我的main.js中没有applyBindings。如果您查看Steve Sanderson's Knockout Triage repo

,这将适用于单页面应用程序

我的工作原理是从applyBindings移除main.js,然后在page1.jsrequire(["jquery", "knockout", "js/main"], function($, ko)中要求它们。

理想情况下,这些组件将在全球范围内注册,我甚至不必在页面级别考虑它们,但是嘿嘿。我确实有一个工作示例,我昨天在工作中做了(但我忘了抓一份我的代码)并且工作正常。

2 个答案:

答案 0 :(得分:2)

如果您要对一组淘汰组件进行标准化,我建议在模块内注册组件。在下面的示例中,代码使用special 'exports' dependency来定义模块的返回值。这减少了在模块末尾有 return 语句的需要。

define([
  'knockout', 
  'exports', 
  'text!/.select-text.html'
], function (ko, selectArea, template) {

   function SelectArea(params) { ... }

   selectArea.viewModel = SelectArea; 
   selectArea.template = template;

   ko.components.register('select-area', selectArea);

});

在模块内部注册组件的好处是,所有内容都是独立的,并且可以记录。然后,如果您有许多组件,则可以创建一个简单的 all.js 模块以包含所有组件定义。 e.g。

define([
  'components/selectArea',
  'components/selectMultiple',
  ....
 ], function () { });

然后只需在 require()调用中包含 all.js ,或者调用 ko的 define()块.applyBindings(),并且在调用ko.applyBindings()之前应该注册所有组件。

require([
  'knockout',
  ...
  'components/all'
], function (ko, ...) {
   ko.applyBindings(...);
}

如果您有某些特定于页面的组件,则可能需要更改此模式。还有一点需要注意,尽量不要让淘汰组件AMD模块有任何副作用。它应该只定义视图模型和模板。

答案 1 :(得分:0)

From the comments it was made clear to not applyBindings in my main.js. This would work in single page application if you look at Steve Sanderson's Knockout Triage repo

How I got it working was to remove the applyBindings from main.js but then require them in page1.js: require(["jquery", "knockout", "js/main"], function($, ko).

Ideally the components would be registered globally and I wouldn't even have to consider them on a page level but hey-ho. I do have a working example I did at work yesterday (but I forgot to grab a copy of my code) and had it working fine.