ko.plus is a collection of extensions to KnockoutJs that add to the core library.
Get the ko.plus package from NuGet.
Install-Package ko.plus
ko.command creates a representation of a command that exposes isRunning
, failed
and other observable properties to allow binding to command state.
The created commands can be invoked directly (as you would a normal function) and as such can be bound to the click
handler.
They support both sychronous and asynchronous implementation code, and expose done
, fail
and always
methods to allow continuations.
function ViewModel() {
this.doSomething = ko.command(function() {
return $.get("...");
})
.done(function(data) {
//do something with the response
})
.fail(function(error) {
//handle the error
});
}
The state properties can be bound in the UI:
<span data-bind="visible: doSomething.isRunning">Loading...</span>
<span data-bind="visible: doSomething.failed">Something went wrong!</span>
The action function can be specified as the single parameter passed to ko.command
or as the action
property on an options object passed into the function.
ko.command(function() { /*...*/ });
//or
ko.command({
action: function() { /*...*/ })
});
An optional canExecute
function can be specified to determine whether or not a command can currently be executed.
function ViewModel() {
this.doSomething = ko.command({
action: function() {
return $.get("...");
},
canExecute: function() {
//validation logic
return true;
}
});
}
Note: the function passed as canExecute
will be wrapped in a ko.computed
, so if it uses other observable properties it will automatically be updated.
If you need to manually inform a command that the value of canExecute
has changed then you can call the canExecuteHasMutated
function, which will force a reevaluation.
The context
option sets the context in which the callbacks and action functions will be executed.
function ViewModel() {
this.url = "...";
this.doSomething = ko.command({
action: function() {
return $.get(this.url);
},
context: this
});
}
An observable that indicates whether or not the command is currently running.
A computed observable that indicates whether or not the command is currently able to execute.
An observable that indicates whether or not the last invocation of the command failed.
Attach a callback that will be invoked when the command completes successfully.
Attach a callback that will be invoked when the command fails.
Attach a callback that will be invoked when the command either completes successfully or fails.
ko.editable creates an extendion of ko.observable
with some additional properties to aid in beginning, cancelling and committing changes.
ko.editableArray does the same for instances of ko.observableArray
.
function ViewModel() {
this.value = ko.editable(123);
}
var instance = new ViewModel();
//instance.value -> 123
instance.value.beginEdit();
instance.value(456);
//instance.value -> 456
instance.value.cancelEdit();
//instance.value -> 123
An observable property that indicates whether or not the editable is currently in edit mode.
Puts the editable into edit mode.
Takes the editable out of edit mode, commiting any changes.
Takes the editable out of edit mode and reverts to value at the point when beginEdit
was called.
Without changing edit state, reverts back through historically committed values for this editable until it reaches the original value.
ko.makeEditable adds to the functionality of ko.editable
and ko.editableArray
(which only apply to single properties) and expands to allow object graphs to be editable.
This works by appending beginEdit
, cancelEdit
, endEdit
and rollback
methods to the target object that will visit all child properties and, if they are editable, invoke the appropriate function.
The function will be applied recursively to:
- immediate child properties that are editable (whether instances of
ko.editable
or other editable view models) - any editable objects found in child arrays (either editable arrays or normal)
function ViewModel() {
this.property1 = ko.editable();
this.property2 = ko.editable();
this.arrayProperty = ko.editableArray([
ko.editable(),
ko.editable()
]);
ko.editable.makeEditable(this);
}
var instance = new ViewModel();
instance.beginEdit();
instance.property1.isEditing(); // -> true
instance.property2.isEditing(); // -> true
instance.property1.isEditing(); // -> true
An observable property that indicates whether or not the editable is currently in edit mode.
Puts the editable and all child editables into edit mode.
Takes the editable and all child editables out of edit mode, commiting any changes.
Takes the editable and all child editables out of edit mode and reverts to value at the point when beginEdit
was called.
Without changing edit state, reverts back through historically committed values for this editable until it reaches the original value for all child editables.
The loadingWhen
custom binding handler replaces the contents of a container element with a loading placeholder when the bound value is truthy.
<div data-bind="loadingWhen: someAction.isRunning">
<p>This will content will be replaced when someAction.isRunning</p>
</div>
The loading element is automatically assigned the .loader
class (defined in ko.plus.css
).
The loaderClass
property specifies what additional class will be assigned to the loading element that sets the loading spinner.
The default option is loader-dark
(grey spinner on a transparent background), and the default ko.plus.css
stylesheet contains a loader-white
option (white spinner on a transparent background).
Non-default loader classes can also be assigned.
Whilst primarily designed for container elements (div
, ul
, etc.) the loadingWhen
binding will also work with elements that directly contain text (button
, a
, etc.).
By default the loading spinner will overlay itself over the text in these scenarios. For a slightly better appearance, try setting a specific background colour on the element to "hide" the text content. For example, if you have a
elements on a white background you could use the following:
/* CSS */
a > .loader { background-color: white; }
<!-- HTML -->
<body>
<!-- "Click Me" will be hidden by the white background whilst command is running -->
<a href="#" data-bind="click: command, loadingWhen: command.isRunning">Click Me</a>
</body>
Important note: don't change the background-image
- this is needed to display the loading spinner.
The command
custom binding handler applies the following bindings for a ko.command
instance specified through the valueAccessor
:
click
bound to the commandloadingWhen
bound tocommand.isRunning
enable
bound tocommand.canExecute
<button data-bind="command: someAction">Do Something</button>