Alex Dresko
Alex Dresko

Reputation: 5203

Knockout click binding with javascript confirm

I can't figure out how to create a knockout click binding that doesn't execute the valueAccessor unless a javascript confirm dialog returns true.

It's probably look something like this:

<a data-bind="confirmClick: { message: 'Are you sure?', click: someMethod }">Confirmable link</a>

Internally, the confirmClick binding would do something like:

if (confirm(message)) {
   click();
}

I know I could get around having to do this by putting the confirm(...) code in my viewModel, but that doesn't seem like the appropriate place to put that kind of code. I could probably also go as far as to do this kind of confirm dialog with jQueryUI or Bootstrap, but I want something I can just drop into any project.

I've scoured the internets with no luck.. I even looked at the source code for knockout's click event (https://github.com/knockout/knockout/blob/master/src/binding/defaultBindings/event.js), but it doesn't look friendly at all...

Any help at all would be greatly appreciated!

Upvotes: 14

Views: 6515

Answers (2)

nemesv
nemesv

Reputation: 139768

You need to create your custom confirmClick binding handler which takes your message and your click handler and wrap around the confirmation logic:

ko.bindingHandlers.confirmClick = {
    init: function(element, valueAccessor, allBindings, viewModel) {
        var value = valueAccessor();
        var message = ko.unwrap(value.message);
        var click = value.click;
        ko.applyBindingsToNode(element, { click: function () {
            if (confirm(message))
                return click.apply(this, Array.prototype.slice.apply(arguments));
        }}, viewModel);
    }
}

And you can you it like you have described:

<a data-bind="confirmClick: { message: 'Are you sure?', click: someMethod }">
    Confirmable link</a>

Demo JSFiddle.

Note: You only need the click.apply magic if you want to preserve and pass over the original click event handler args to your own click event handler.

Upvotes: 24

PW Kad
PW Kad

Reputation: 14995

I believe this is where Knockout defines the click binding handler -

ko.bindingHandlers[eventName] = {
    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var newValueAccessor = function () {
            var result = {};
            result[eventName] = valueAccessor();
            return result;
        };
        return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
    }
}

Where eventName is 'click' for that binding handler. I believe that putting this somewhere in your view model or after Knockout is loaded should do the trick -

ko.bindingHandlers.clickConfirm = {
    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var newValueAccessor = function () {
            var result = {};
            result.click = function () {
             var result = confirm('You are about to confirm something.');
                // If they press OK,
                console.log('pressed - ', result);
                if (result === true) {
                    console.log('Calling this - ', valueAccessor());
                    valueAccessor()();
                }

            }
            return result;
        };
        return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
    }
}

http://jsfiddle.net/XhLKD/

Upvotes: 0

Related Questions