在“beforeChange”订阅中获取可观察量的新值

时间:2016-12-29 08:10:11

标签: knockout.js knockout-2.0

我知道有get the new value of an observable in a subscribe event的解决方案(在实际更改之后),但我想知道是否可以在“beforeChange”订阅中访问observable的新值。

以下是current version of Knockout(3.4.1)的片段,分别使用旧值和新值引发beforeChange和afterChange订阅处理程序:

if (computedObservable.isDifferent(state.latestValue, newValue)) {
    if (!state.isSleeping) {
        computedObservable["notifySubscribers"](state.latestValue, "beforeChange");
    }

    state.latestValue = newValue;
    if (DEBUG) computedObservable._latestValue = newValue;

    if (state.isSleeping) {
        computedObservable.updateVersion();
    } else if (notifyChange) {
        computedObservable["notifySubscribers"](state.latestValue);
    }

    changed = true;
}

显然newValue在“beforeChange”可用,所以我觉得分叉是一个选项,但我不愿意。

有没有其他解决方案可以获得这个新值“beforeChange”?

3 个答案:

答案 0 :(得分:1)

修改:我刚刚重新阅读您的问题并认为您可能意味着要在设置之前检查新值?如果是这种情况,您可能希望执行this之类的操作。

我通常创建两个订阅和一个额外的变量来跟踪旧的(你可能已经尝试过):

var myObs = ko.observable(1);

// Keep track of old
var myObsOld = myObs();
myObs.subscribe(function(oldVal) {
  myObsOld = oldVal;
}, null, "beforeChange");

// Subscribe to new
myObs.subscribe(function(newVal) {
  console.log("myObs changed from", myObsOld, "to", newVal);
});

myObs(2);
myObs(3);
.as-console-wrapper { min-height: 100%; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

现在,如果您不想使用额外的变量和订阅来丢弃您的viewmodel,您可以将此逻辑封装在扩展器中:

ko.extenders.latestValue = function(target, option) {
  target.latestValue = target();
  
  target.subscribe(function(oldVal) {
    target.latestValue = oldVal;  
  }, null, "beforeChange");
  
  return target;
};

var myObs2 = ko.observable("a").extend({ latestValue: true });
myObs2.subscribe(function(newVal) {
  console.log("myObs2 changed from", myObs2.latestValue, "to", newVal);
});

myObs2("b");
myObs2("c");
.as-console-wrapper { min-height: 100%; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

不是一种非常性感的方法,但我认为它比分配回购更好:)

答案 1 :(得分:1)

注意:此答案基于您对问题的评论,而不是原始问题。

当更改observable时,它会调用名为notifySubscribers的observable上的方法,该方法执行实际通知,从而更新依赖于该observable的任何计算的observable,bindings等。如果你想在任何这些通知之前做一些事情,你有几个选择。

  1. 如@ user3297291所述,请使用Ryan Niemeyer的protectedObservable

  2. 在任何其他任何订阅之前立即订阅observable。订阅者总是按顺序调用,因此您的代码将始终先运行。

  3. 覆盖notifySubscribers以挂钩通知流程(请记得调用上一个方法)。

  4. 可能对于Knockout 3.5.0,在change事件之前会发生a spectate event

答案 2 :(得分:0)

这并非完全响应您的请求,但对于稍微不同的用例可能有用。

如果您不坚持在更改传播到可观察对象之前触发订阅,并与beforeChange订阅一起触发,则可以创建自己的订阅,将新值和新值一起推送到回调中。

此订阅是在更改发生后触发的,它只是一起提供以前和当前的值。

/** 
 * extended version of knockout subscription provides to callback function new and previous value at once
 * function Callback(newValue, originalValue) {...}
 * 
 * @param {Function} callback function called on observable change
 * @param {Object} context of the callback
 * @return {Object} instance of changed subscription
 */
ko.subscribable.fn.subscribeChanged = function (callback, context) {
    var savedValue = this.peek();
    return this.subscribe(function (latestValue) {
        var oldValue = savedValue;
        savedValue = latestValue;
        callback(latestValue, oldValue);
    }, context);
};