Knockout.js - 组件之间的发布/订阅,双向对话

时间:2016-08-16 21:41:18

标签: javascript knockout.js

我的Knockout应用程序由代表表单不同部分的不同组件组成 - 所以我有一个"语言"组件,a"国家"组件,a"标签"组件等。在每个组件中,我都有一个可观察的数组,我订阅并通过ko.postbox.notifySubscribers在这些可观察量发生变化时发送通知。在另一个名为filters的组件中,它充当用户在表单中选择的所有过滤器的收集器,我通过ko.postbox.subscribe接收这些observable中的更改。

我的问题是:如果我想在过滤器组件中进行更改并将它们反映在其他组件中,该怎么办?也就是说,如何在双向对话中改变这种单向对话?

例如,在语言组件中,我有一个下拉菜单,用户选择语言。在过滤器菜单中,我有所选语言的列表(复选框),我希望用户能够从这里取消选择项目,同时仍然更新主要组件中的下拉列表。

发布语言组件和过滤器组件的代码, 感谢

Languages.js

ko.components.register("languages",{ 
 viewModel: function(){
  var self            = this;
  self.languages      = ko.observableArray();
  self.selectedLangs  = ko.observableArray();

  xhr.languages()
   .done(function (langs) {
     self.languages(langs);
  }); 

  self.selectedLangs.subscribe(function(values) {
    ko.postbox.notifySubscribers(
     _.map(values,function(val){
      var obj = _.findWhere(self.languages(), {id: val});
      return obj.text;
    }), "selectedLangs");
  });
},
template: 
'<fieldset id="language" class="wfp-u-1">\
  <div class="wfp-grid">\
    <label for="dss-language" class="wfp-u-1 wfp-u-lg-1-4">\
      Language <span class="loader"><i class="icon-loader"></i></span>\
      <em>Multiselection available</em>\
    </label>\
    <select id="dss-language" name="language" multiple="" class="wfp-u-1 wfp-u-lg-3-4 ui dropdown search selection"\
      data-bind="\
        options: languages,\
        optionsText: \'text\',\
        optionsValue: \'id\',\
        optionsCaption: \'Select one or more languages\',\
        selectedOptions: selectedLangs\">\
    </select>\
  </div>\
</fieldset>'
});

Filters.js

ko.components.register("filters",{ 
 viewModel: function(){

var self = this;
self.selectedLangs      = ko.observableArray();

ko.postbox.subscribe(function(langs) {     
  self.selectedLangs(langs);
}, self, "selectedLangs");
},
template: 
'<ul class="wfpList wfpFieldList mCustomScrollbar">\
  <li>\
    <a data-target="language">Language</a><i class="ico-angle-down"></i>\
    <!-- ko foreach: selectedLangs -->\
      <span data-bind="text: $data"></span>\
    <!-- /ko -->\
  </li>\
</ul>'
});

1 个答案:

答案 0 :(得分:1)

复制John Papa的回答(https://stackoverflow.com/a/10818849/1287183):

  

一个选项是创建一个隔离的datacontext来维护可观察的模型。 viewmodels都会查看datacontext的数据并引用相同的对象,所以当一个更新时,它们都会这样做。 VM的依赖关系在datacontext上,但不在其他VM上。我最近一直这样做,而且运作良好。