Skip to content Skip to sidebar Skip to footer

How To Define A Custom Binding Who Use Previous Value To Determine Class In Knockout?

I need to bind a table with knockout, and I would like the table cell to get a different css class if the new value is higher or lower of the previous. I have in mind different pos

Solution 1:

Although Jeff's and SÅ‚awomir's answers would work, I found an alternative that doesn't need any change to the view model nor relies on altering the DOM element object.

functionsubscribeToPreviousValue(observable, fn) {
  observable.subscribe(fn, this, 'beforeChange');
}

ko.bindingHandlers['bindingWithPrevValue'] = {
  init: function (element, valueAccessor) {
    var observable = valueAccessor();
    var current = observable();

    console.log('initial value is', current);

    subscribeToPreviousValue(observable, function (previous) {
      console.log('value changed from', previous, 'to', current);
    });
  }
};

Naturally, that will only work if the bound property is an observable.

Solution 2:

I looked into knockout source and I suppose that you can't access previous value inside update method of bindingHandler but you can store it inside element

ko.bindingHandlers['bindingWithPrevValue'] = {
    update: function (element, valueAccessor) {
        var prevValue = $(element).data('prevValue');
        var currentValue = valueAccessor();
        $(element).data('prevValue', currentValue());

        // compare prevValue with currentValue and do what you want
    }
};

Solution 3:

What you could do is create an extender to extend the observables that you wish to track the previous values of. You could then inspect the previous value to do as you wish.

Just pass in the name of the property that will hold the previous value.

ko.extenders.previousValue = function (target, propertyName) {
    var previousValue = ko.observable(null);

    target[propertyName] = ko.computed(previousValue);

    target.subscribe(function (oldValue) {
        previousValue(oldValue);
    }, target, 'beforeChange');

    return target;
};

Then to use it:

functionViewModel() {
    this.value = ko.observable('foo').extend({ previousValue: 'previousValue' });
}

var vm = newViewModel();

console.log(vm.value()); // 'foo'console.log(vm.value.previousValue()); // null

vm.value('bar');

console.log(vm.value()); // 'bar'console.log(vm.value.previousValue()); // 'foo'

In your case, you could probably use something like this:

function TableCell(value) {
    this.value = ko.observable(value).extend({ previousValue: 'previousValue' });
    this.cssClass = ko.computed(function () {
        // I'm assuming numbersvar current = Number(this.value()),
            previous = Number(this.value.previousValue());

        if (current < previous)
            return'lower';
        elseif (current > previous)
            return'higher';
    }, this);
}

Post a Comment for "How To Define A Custom Binding Who Use Previous Value To Determine Class In Knockout?"