7

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.

beauXjames
  • 8,222
  • 3
  • 49
  • 66
  • You subscribe method called, when your observableArray has changed (added or deleted items), yes? If it is true, maybe you should to add two methods add/delete, and make validation inside them? – alexmac Dec 19 '13 at 21:15

2 Answers2

4

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");
RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211
  • Yeah, which isn't far from how I am currently handling it. I did like the idea of keeping my requests to the server directly attached to the change of the object(s) I'm sending over as they change. Thanks for taking a moment to share the idea. – beauXjames Dec 20 '13 at 03:33
2

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));
Pavel Kutakov
  • 971
  • 1
  • 7
  • 11
  • Very nice use of the extender to alter the input. I did a little addition of the same subscribe logic to test what order events occurred. I found that the extender does, in fact, occur before the subscription however the 'changes' returned to the subscription were now void of the 3.0 change inspection method. http://jsfiddle.net/n2APg/4 – beauXjames Dec 20 '13 at 14:23
  • It just adds one line: myVM.Data.push(13); – BenjiFB Dec 24 '14 at 20:28
  • But it fails with this error: Error: Object doesn't support property or method 'push'. When I take off the "extend" part of the observableArray, it works correctly. Why does this solution break my ability to programmatically push an element? Is there any way to get this functionality back? – BenjiFB Dec 24 '14 at 20:29