Knockout:引用组件A从组件B调用A函数之一?

时间:2016-11-22 23:37:25

标签: javascript knockout.js single-page-application yeoman js-amd

使用了Yeoman的Knockout生成器(2015年初,c .a。),其中包括require.js和router.js。只需使用KO的装载机。

我试图在组件" a"中调用一个函数(ko.observable与否)。 来自 组件" b"。 下面的所有绒毛都试图做:

// In componentB:

ComponentA.sayFoo();

阅读关于组件和加载器的KO文档,黑客攻击了几个小时等等。我不想要 postal.js 的开销 - 而且也无法获得订阅(KO pub / sub) )工作 - 我猜是出于同样的原因:以这种方式设置的视图模型没有相互引用(?) - 因此一个模块中的订阅者不会在另一个模块中看到发布者(右) ?)(......我头脑中有点% - )

1)这是因为模块没有看到对方......这个生成的代码没有将KO内容放在全局命名空间中吗?

2)尝试从一个模块到另一个模块,似乎取决于通过回调参数获取参考,使用下面的功能,还是不正确? :

  ko.components.get (name, callback) ;
使用require的

startup.js 如下所示:

define(['jquery', 'knockout', './router', 'bootstrap', 'knockout-projections'], function($, ko, router) {

// Components can be packaged as AMD modules, such as the following:

   ko.components.register('component-a', { require: 'components/a/component-a' });  
   ko.components.register('component-b', { require: 'components/b/component-b' });  

// [Scaffolded component registrations will be inserted here. To retain this feature, don't remove this comment.]
// [Scaffold component's N/A (I think?)] 

// Start the application
   ko.applyBindings({ route: router.currentRoute });  
});

(组件)模块 A是直截了当的,如下所示:

define(['knockout', 'text!./component-a'], function(ko, templateMarkup) {

   function ComponentA (params) { console.log ('CompA'); } ;

   ComponentA.prototype.sayFoo  = function () { console.log ('FOO!'); } ;
   ComponentA.prototype.dispose = function(){};

   return { viewModel: ComponentA, template: templateMarkup };
});

同样,模块 B 是:

define(['knockout', 'text!./component-b'], function(ko, templateMarkup) {

   function ComponentB (params) { console.log ('Compb'); } ;

   ComponentB.prototype.doFoo  = function () { 
     //// B Needs to fire ComponentA.foo() … SEE CODE ATTEMPT BELOW 
   };

   ComponentB.prototype.dispose = function(){};

   return { viewModel: ComponentB, template: templateMarkup };
});

所以这就是我被困的地方:

  ComponentB.prototype.doFoo  = function () { 
        ko.components.get ('component-a', ( function (parms) {
           console.log ('parms.viewModel : ' + parms.viewModel );  
           // parms.viewModel is (unexpectedly) undefined ! So how to get the ref?
           console.log ('parms.template : ' + parms.template );  
          // does have expected html objects, eg. [object HTMLwhatever], [object HTML...]
 })) ; 

这应该很容易,或者我愚蠢地遗漏了一些明显的东西!?

可能需要以不同的方式定义/设置模块吗?

任何建议都会有所帮助! THX

2 个答案:

答案 0 :(得分:2)

这不是你在淘汰赛组件之间正常沟通的方式。

您的选择是:

1)使用https://github.com/rniemeyer/knockout-postbox。这可能是最好的选择,因为它与淘汰赛很好地融为一体。它有详细记录,如果你设置麻烦,你可以随时寻求帮助。

2)使用任何其他全局javascript EventBus(f.i。postal.js)并发出/订阅组件中的事件。

3)让你的根ViewModel将公共observable传递给每个组件作为参数 - 这样每个组件都可以修改/订阅相同的observable。

4)(可能你想要的,尽管是最差的扩展解决方案)如果你给不同组件的id,你可以使用ko.dataFor(document.getElementById("id"))直接访问组件的属性和方法。

编辑:回应评论:

  

我没有   能够确定根视图模型的位置/位置:   ko.applyBindings({route:router.currentRoute})是线索,但是   router.js是错综复杂的。关于如何确定的建议?

确实 - 在您的情况下,{ route: router.currentRoute }对象是您的根ViewModel。它目前只有一个名为route的属性,但你绝对可以扩展它。

例如:

var rootViewModel = {
    route: router.currentRoute,
    mySharedObservable: ko.observable('hi!')
}

ko.applyBindings(rootViewModel);

然后你可以将这个observable作为参数传递给多个组件:

<div id="component-a" data-bind="component: { name: 'component-a', params: {router: $root.router, mySharedObservable: $root.mySharedObservable} }"></div>
<div id="component-b" data-bind="component: { name: 'component-b', params: {router: $root.router, mySharedObservable: $root.mySharedObservable} }"></div>

最后,您可以在组件中使用新的observable,如下所示:

function ComponentB (params) { 
    this.mySharedObservable = params && params.mySharedObservable;
    console.log(this.mySharedObservable());// This should log 'hi!'
};

您现在可以订阅observable,更改它等等。它将在组件之间共享,因此将其更改为一个组件将触发所有组件中的订阅。

答案 1 :(得分:1)

我的标准方法是通过父虚拟机控制通信。

父虚拟机可以创建一个可订阅的[1],并将其作为参数传递给componentA和componentB;然后ComponentA可以订阅可订阅的,而ComponentB可以触发可订阅的。

//ComponentA
function ComponentA (params) { 
    var shouldSayFoo = params.shouldSayFoo;

    this.shouldSayFooSubscription = shouldSayFoo.subscribe(function () {
        this.sayFoo();
    });
} ;

ComponentA.prototype.sayFoo  = function () { console.log ('FOO!'); } ;
ComponentA.prototype.dispose = function () { this.shouldSayFooSubscription.dispose(); };

//In ComponentB
function ComponentB (params) {
    this._triggerFoo = params.triggerFoo; //Same subscribable as shouldSayFoo in ComponentA
}

ComponentB.prototype.doFoo = function () {
    this._triggerFoo.notifySubscribers(); //notifySubscribers triggers any .subscription callbacks
}

如果ComponentA和ComponentB是兄弟姐妹并且你不是一直都在做这种事情,那么这就是一个非常简单的解决方案。如果组件是“远房亲戚”或者如果你发现自己做了很多,那么我会建议某种pub-sub。这种方法的一个优点是可以被许多单独的“A-B”对使用而不会相互干扰,这对于pub-sub系统来说更难。

[1]:ko.subscribable是一个具有可观察功能子集的对象(ko.observable继承自ko.subscribable):它不允许您读取或写入值,但是允许您执行.subscribe.notifySubscribers。 (由于某种原因,它们是用new创建的。你也可以使用一个observable,如果你不打算保留一个值,那么创建一个observable的意图就会略微混淆。