// I still need to figure out how to pass the viewModel to the canExecute() function when it is a ko.computed() function.
ko.bindingHandlers.koCommandButton = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContenxt) {
$(element).button();
var valueUnwrapped = ko.utils.unwrapObservable(valueAccessor());
$(element).click(function () {
valueUnwrapped.execute(viewModel);
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var valueUnwrapped = ko.utils.unwrapObservable(valueAccessor());
if (ko.isObservable(valueUnwrapped.text)) {
text = ko.utils.unwrapObservable(valueUnwrapped.text());
} else {
text = valueUnwrapped.text || "[text]";
}
$(element).text(text);
if (valueUnwrapped.canExecute()) {
$(element).button("enable");
} else {
$(element).button("disable");
}
}
};
function Command(options) {
var defaults = {
canExecute: function (data) {
return true;
},
execute: function (data) {
alert("No command execution function has been assigned.");
},
text: "[text]"
};
var settings = $.extend({}, defaults, options);
var api = {
text: ko.observable(settings.text),
canExecute: ko.computed(settings.canExecute),
execute: settings.execute
};
return api;
}
function ViewModel() {
var isChecked = ko.observable(false);
function hideDetails() {
$(".details").hide();
}
var api = {
text: ko.observable("title"),
isChecked: isChecked,
commandObject: new Command({
canExecute: function (data) {
return isChecked();
},
execute: function (data) {
hideDetails();
$("#commandObjectDetails").fadeIn(500);
},
text: ko.observable("command")
}),
staticCommand: {
canExecute: function (data) {
return isChecked();
},
execute: function (data) {
hideDetails();
$("#staticObjectDetails").fadeIn(500);
},
text: "static"
},
dynamicObservableCommand: {
self: this,
canExecute: ko.computed(function () {
return isChecked();
}),
execute: function (data) {
hideDetails();
$("#dynamicObservableObjectDetails").fadeIn(500);
},
text: ko.observable("dynamicObservable")
}
};
return api;
}
$(function () {
try {
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
$("#canExecute").click(function () {
var value = $("#canExecute").prop("checked");
viewModel.isChecked(value);
});
} catch (error) {
alert(error);
}
});
External resources loaded into this fiddle:
<div id="template"> <a href="#" data-bind="koCommandButton: commandObject"></a>
<a href="#"
data-bind="koCommandButton: staticCommand"></a> <a href="#" data-bind="koCommandButton: dynamicObservableCommand"></a>
<label
for="canExecute">Enable / Disable Buttons</label>
<input type="checkbox" id="canExecute"
/>
<div id="content">
<div id="commandObjectDetails" class="details" style="display:none;">
<p>This command is an implementation of a js Command class with a ko.observable()
text property and static canExecute and execute methods.</p>
</div>
<div id="staticObjectDetails" class="details" style="display:none">
<p>This staticCommand is an object literal without any ko.observable() properties
of any kind.</p>
</div>
<div id="dynamicObservableObjectDetails" class="details" style="display:none">
<p>The dynamicObservable command is an object literal and uses a ko.computed()
canExecute() method and ko.observable() text property.</p>
</div>
</div>
</div>