Reputation: 5203
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
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
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);
}
}
Upvotes: 0