How might I cancel a change to an observable array w/ Knockout 3.0?

6k Views Asked by At

I have a change occurring to an array. I am using Sanderson's latest array subscription method to catch the add/delete change. In this subscription is where I intend to bundle and send my request over the wire. If the request fails for any reason I want to be able to cancel any possible changes to the collection. I have verified that this subscription is hit before the change propagates so I assume there would be a way to say "STOP DON'T DO IT" however I can't figure out how.

As my example...

self.SourceData = ko.observableArray(data);
self.SourceData.subscribe(function(changes) {
    var isAllGood = true;
    ko.utils.arrayForEach(changes, function(ch) {
        if (ch.value == doesNotMeetMyCondition) isAllGood = false;
    });
    if (!isAllGood) <STOP DON'T DO IT>
}, null, 'arrayChange');

When inspecting 'this' I do see the ko.subscription object with the standard [callback, dispose, disposeCallback, target] but nothing seems to amount to STOP DON'T DO IT.

Any thoughts would be quite helpful. Thanks.

2

There are 2 best solutions below

1
On

There is not currently a way to stop the change from going through.

You could potentially subscribe to the beforeChange event and cache a copy of the array before the change. Something like:

self.SourceData.subscribe(function(value) {
    /store copy, in case it needs to be restored
    self.beforeSourceData = value && value.slice();
}, null, "beforeChange");
3
On

You can use another approach - create extender to validate your array on change. I've created simplified example that checks simple array of integers for specified upper boundary. Fiddle: http://jsfiddle.net/pkutakov/n2APg/1/ Code:

ko.extenders.checkValue=function (value, condition){
    var result=ko.computed({
        read: value,
        write: function (newValue){
            var current=value();
            var canSave=true;
            ko.utils.arrayForEach(newValue, function(ch) {
                if (ch>condition)
                    canSave=false;
            });
            if (canSave)
            {
                value(newValue);
                value.notifySubscribers(newValue);
            }
            else
                value.notifySubscribers(value());
        }
    }).extend({ notify: 'always'});
    result(value());

    //return the new computed observable
    return result;
}

function AppViewModel(data)
{
    self=this;
    self.Data=ko.observableArray(data).extend({ checkValue: 100});
}

var mydata=[10, 11];
ko.applyBindings(new AppViewModel(mydata));