Command pattern
Use the command pattern to encapsulate UI actions into reusable, testable objects when extending widgets, toolbars, and actions in Optimizely CMS.
The command pattern encapsulates UI actions into reusable objects. This separates execution logic from concrete widgets into a testable unit. A single command can have multiple UI objects that trigger its execution.
The command base class is epi/shell/command/_Command.
Command base methods
The command base exposes a public execute method and two protected methods that define command behavior.
The public execute method runs the action when canExecute is true. Interface objects associated with the command typically call this method.
Override the following protected methods in implementing classes:
_execute– Defines the execution logic. Called byexecuteafter confirming the command is executable._onModelChange– Updates the state ofcanExecutebased on the model object. Called when a model is set on the command.
Stateful commands
Commands are stateful, which means other objects can watch for changes to command properties. Watch canExecute to update the display state of interface objects that represent the command. Set the model with set("model", value) to trigger _onModelChange, which updates canExecute for the model.
NoteA stateless protocol does not require the server to retain session information for the duration of multiple requests. A stateful protocol requires the server to keep internal state. Source: Wikipedia
Example implementation
The following code sample shows a command implementation:
define([
"dojo/_base/declare",
"epi/dependency",
"epi/shell/command/_Command"
],
function (declare, dependency, _Command) {
return declare([_Command], {
constructor: function () {
// summary:
// Constructs the object and sets up a reference to the content data store.
// tags:
// public
var registry = dependency.resolve("epi.storeregistry");
this.store = registry.get("epi.cms.contentdata");
},
_execute: function () {
// summary:
// Executes this command assuming canExecute has been checked.
// tags:
// protected
var model = this.model;
model.isCommonDraft = true;
return this.store.put(model);
},
_onModelChange: function () {
// summary:
// Updates canExecute after the model has been updated.
// tags:
// protected
var model = this.model,
canExecute = model && !model.isCommonDraft;
this.set("canExecute", canExecute);
}
});
}
);Command providers and consumers
The provider and consumer pattern separates where commands originate from where they display. This extends the principle of separation of concerns.
A widget that provides commands is not responsible for displaying them. For example, the page tree provides commands such as create page and translate page. The page tree does not control where or how those commands display. The component chrome that contains the page tree handles command display. Because the page tree has no reference to the component chrome, a generic method bridges the two.
The epi/shell/command/_CommandProviderMixin and epi/shell/command/_CommandConsumerMixin classes link the command source to the display location. The provider maintains a list of commands. The consumer maintains a list of command providers and displays their commands.
Updated 17 days ago
