knockout / knockout

Knockout makes it easier to create rich, responsive UIs with JavaScript
http://knockoutjs.com/
Other
10.47k stars 1.51k forks source link

subscription of computed observable triggered even when value is same #1884

Closed fastfasterfastest closed 9 years ago

fastfasterfastest commented 9 years ago

I have a pureComputed that returns a javascript Date object. I register a subscription to the pureComputed's changes using .subscribe. However, the subscription is triggered even when the same value is returned by the pureComputed.

The reason is explained at http://knockoutjs.com/documentation/computedObservables.html which states:

When a computed observable returns a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed.

My pureComputed does not hold a "primitive value", but instead a javascript Date object. Would it be reasonable to request knockout to handle a javascript Date object the same way as it currently handles "primitive values" (perhaps by using .valueOf())?

mbest commented 9 years ago

This isn't documented, but you can change how an observable determines whether values are equal by setting the equalityComparer method of the observable:

myObservable.equalityComparer = function(a, b) {
    if (a instanceof Date && b instanceof Date) {
        return a.toDateString() == b.toDateString();
    } else {
        return ko.observable.fn.equalityComparer(a, b);
    }
};

If you want to affect all observables or computed observables, you can modify ko.observable.fn.equalityComparer or ko.computed.fn.equalityComparer directly.

fastfasterfastest commented 9 years ago

Thanks. Interestingly, the observable I use to compute the value to return in the pureComputed was already using such an equalityComparer. That observable holds a Date object and I install an equalityComparer on it for that very purpose. I did that a quite some time ago and had forgotten about it. In this case, I also need to install such an equalityComparer on the pureComputed. Thanks for suggesting that!

Nevertheless, I think it might be a good idea if knockout (out of the box) considered two intrinsic Date object equal if they both have the same value.

By the way, I used a.valueOf() === b.valueOf(), instead of a.toDateString() == b.toDateString(), as a micro-optimization.

mbest commented 9 years ago

I'm glad you've got it working.