【问题标题】:KnockoutJS subscribe to multiple observables with same callback actionKnockoutJS 订阅多个具有相同回调操作的 observables
【发布时间】:2012-02-14 14:21:12
【问题描述】:

我在 KnockoutJS 中有一个模型类,它有多个我想订阅的值。每个订阅都将执行相同的任务,如下所示:

function CaseAssignmentZipCode(zipCode, userId, isNew) {
  var self = this;
  self.zipCode = ko.observable(zipCode);
  self.userId = ko.observable(userId);
  self.isNew = isNew;
  self.isUpdated = false;

  self.zipCode.subscribe(function () { self.isUpdated = true; });
  self.userId.subscribe(function () { self.isUpdated = true; });
}

有没有办法将这两个调用结合起来进行订阅,以便我可以使用一个订阅来“观察”两个值?

【问题讨论】:

标签: javascript knockout.js


【解决方案1】:

您可以为此目的使用计算的 observable。你只需要确保你访问了 read 函数中每个 observable 的值。会是这样的:

ko.computed(function() {
   self.zipCode();
   self.userId();
   self.isUpdated = true;
});

所以,你获得了两个 observables 的依赖关系并设置了你的标志。

此外,如果您正在寻找类似“脏”标志的东西,那么您可能会考虑类似:http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html。这个想法是你使用一个计算的 observable,它在一个对象上调用 ko.toJS() 来解开它的所有 observables。

【讨论】:

  • 我看过这个解决方案,但我对它不太满意,因为计算并没有真正计算任何东西,所以代码更难理解。
  • 计算过的 observables 不一定需要返回值。依赖跟踪机制有很多用途。例如,Knockout 使用计算来跟踪绑定中的依赖关系。这是最近一篇关于可以使用计算的一些方法的帖子:blog.safaribooksonline.com/2014/02/19/…
  • @RPNiemeyer - 是的,它绝对有效且简洁。我只是对可读性做出反应。
  • 好主意@RPNiemeyer !但是如何使计算不评估 onLoad 但它应该评估类似self.zipCode 的内容是否稍后被修改。我尝试修改邮政编码(绑定到文本框),但计算似乎没有评估。在这里查看jsfiddle.net/LkqTU/27278
  • 不幸的是,没有为此提供明确的工具(例如ko.subscribe([array of observables], callback)。这种方法的缺点是它没有记录在案的用法并且它依赖于副作用计算函数而不是函数的主要目的。因此,这种方法更难理解。在没有专门用于此目的的 API 的情况下,这种模式仍然提供了一种有价值的工具。
【解决方案2】:

您不想复制处理函数的主体吗?将其提取到变量中。

function CaseAssignmentZipCode(zipCode, userId, isNew) {
  var self = this;
  self.zipCode = ko.observable(zipCode);
  self.userId = ko.observable(userId);
  self.isNew = isNew;
  self.isUpdated = false;

  var handler = function () { self.isUpdated = true; };

  self.zipCode.subscribe(handler);
  self.userId.subscribe(handler);
}

【讨论】:

  • 过去,我一直偏爱计算方法。但是当我看到这个时,我觉得在那些时候我可能已经被淘汰赛果汁喝醉了。现在使用淘汰赛构建了许多企业解决方案,这是我的首选方法。
  • 使用计算方法的一个好处是您可以对计算限制使用速率限制
【解决方案3】:

通过将要跟踪的依赖项列表转换为循环来改进将函数体重构为变量:

function CaseAssignmentZipCode(zipCode, userId, isNew) {
  var self = this;
  self.zipCode = ko.observable(zipCode);
  self.userId = ko.observable(userId);
  self.isNew = isNew;
  self.isUpdated = false;

  var handler = function () { self.isUpdated = true; };

  ko.utils.arrayForEach([self.zipCode, self.userId], function(obs) {
    obs.subscribe(handler);
  });
 } 

【讨论】:

    【解决方案4】:

    您可以为此目的创建某种扩展。简单例子:

    function subscribeMany(callback, observables) {    
        for (var i = 0; i < observables.length; i++) {
            observables[i].subscribe(callback);
        }
    }
    

    用法:

    var name = ko.observable();
    var email = ko.observable();
    
    var callback = function(value) {
        console.log(value);
    };
    
    subscribeMany(callback, [name, email]);
    
    name('test 1')
    email('test 2')
    

    【讨论】:

      【解决方案5】:

      Typescript 版本用于对 Observable 列表中的任何 Observable 执行相同的回调。

      此解决方案适用于以下类型:

      1. KnockoutObservableArray&lt;KnockoutObservable&lt;T&gt;&gt;
      2. KnockoutObservable&lt;KnockoutObservable&lt;T&gt;[]&gt;
      3. KnockoutObservable&lt;T&gt;[]

      这种方法的好处:

      1. 如果将 Observable 添加到您的 KnockoutObservableArray 中,则将检测到更改并且订阅功能也将添加到该 Observable。
      2. 相同的解决方案可用于许多不同的类型,并且会为您处理这些类型。

        function subscribeMany<T>(
            observables: KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[],
            callback: (v: T) => void
            ): KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[] {
        
            function _subscribeMany<T>(
                observables: KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[],
                callback: (v: T) => void): void {
        
                if (_isObservableArray<T>(observables)) {
                    _subcribeAndRun(observables, (array) => {
                        array.forEach((observable) => {
                            observable.subscribe(callback);
                        });
                    });
                }
                else {
                    ko.unwrap(observables).forEach((observable) => {
                        observable.subscribe(callback);
                    });
                }
            }
        
            function _isObservableArray<T>(observables: KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> | KnockoutObservable<T>[]): observables is KnockoutObservableArray<KnockoutObservable<T>> | KnockoutObservable<KnockoutObservable<T>[]> {
                return "subscribe" in observables;
            }
        
            function _subcribeAndRun<T>(o: KnockoutObservable<T>, callback: (v: T) => void): KnockoutObservable<T> {
                o.subscribe(callback);
                callback(o());
        
                return o;
            }
        
            _subscribeMany<T>(observables, callback);
            return observables;
        }
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-02
        • 2013-08-02
        • 1970-01-01
        相关资源
        最近更新 更多