blaster
blaster

Reputation: 8937

Knockout - Cancel a Change Event?

I have a checkbox bound to an observable on a view model. I have a requirement to essentially pop up an "Are you sure?" confirmation prompt if the user changes it from true to false. I'm having a horrible time figuring out the best place to make the change "cancelable" . . .

1) jQuery handler for click event 2) Viewmodel internal subscribe "beforeChange" 3) Viewmodel internal subscribe (normal)

In any case, I'd vastly prefer to have the chance to cancel the change outright than react to the change, potentially reverting it back to its previous value if need be.

Does Knockout's subscribe event give you the chance to cancel a change? Any insight would be appreciated. Thanks!

Upvotes: 12

Views: 8691

Answers (2)

mgarciaisaia
mgarciaisaia

Reputation: 15570

Because of the problems commented in @RP Niemeyer answer, I've just implemented this extender:

ko.extenders.confirmable = function(target, options) {
    var message = options.message;
    var unless = options.unless || function() { return false; }
    //create a writeable computed observable to intercept writes to our observable
    var result = ko.computed({
        read: target,  //always return the original observables value
        write: function(newValue) {
            var current = target();

            //ask for confirmation unless you don't have
            if (unless() || confirm(message)) {
                target(newValue);
            } else {
              target.notifySubscribers(current);
            }
        }
    }).extend({ notify: 'always' });

    //return the new computed observable
    return result;
};

You can then apply that to your model like this:

var viewModel = {
    myvalue: ko.observable(false).extend({confirmable: "Are you sure?"});
}

And, if there was a case in which not to ask for confirmation (in this silly example, we'll skip confirmation during March), you can do:

var viewModel = {
    myvalue: ko.observable(false).extend({confirmable: { message: "Are you sure?", unless: function() { return new Date().getMonth() == 2 }} });
}

Upvotes: 15

RP Niemeyer
RP Niemeyer

Reputation: 114792

Here is a simple option using jQuery's stopImmediatePropagation:

http://jsfiddle.net/rniemeyer/cBvXM/

<input type="checkbox" data-bind="click: confirmCheck, checked: myvalue" />

js:

var viewModel = {
    myvalue: ko.observable(false),
    confirmCheck: function(data, event) {
        if (!confirm("Are you sure?")) {
            event.stopImmediatePropagation();            
            return false;
        }
        return true;
    }
};

Upvotes: 22

Related Questions