HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket

Command pattern

Introduces the command pattern used when working with widgets, toolbars, and actions in the Optimizely Content Management System (CMS) user interface.

The command pattern encapsulates interface actions into reusable objects, which separates logic for executing an action from concrete widgets and objects into its own testable unit. One command can have several UI objects that cause the command pattern to execute.

The command base class is epi/shell/command/\_Command.

Methods

The command base has a public execute method that executes the action if canExecute is true. You can explicitly call this, but it is typically called by the interface objects associated with the command.

The command base also has two protected methods that you should override by implementing classes.

  • \_execute is called by execute after checking that the command is in an executable state. Define executional logic for the command in this method.
  • \_onModelChange is called when the model is set on the command and updates the state of canExecute based on the new model object.

Stateful

Commands are stateful so you can watch for changes to their properties. For example, you can watch canExecute, which allows the display state (e.g. enabled/disabled) of interface objects, which represent the command to be updated when canExecute changes. Also, you can set the model on which the command executes or determines it state using set("model", value), which causes the protected \_onModelChange method to be called on the command, which causes the state of canExecute to be updated for the new model.

📘

Note

A stateless protocol does not require the server to retain session information or status about each communications partner for the duration of multiple requests. In contrast, a protocol which requires keeping of the internal state on the server is known as a stateful protocol. Source: Wikipedia

Example

See below for a sample 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

A provider and consumer pattern extends the principle of separating concerns to where the commands are used.

A widget or object that provides commands should not be responsible for displaying them; commands need to appear elsewhere in the interface. For example, the page tree has commands such as create page, translate page, and so on, but the page tree should not be responsible for displaying these because it does not indicate where or how they should be displayed.

Instead, the generic component chrome in which the page tree resides is responsible for displaying the commands. However, the page tree has no reference for the component chrome. You need a generic method to get the commands from the page tree to the component chrome.

The epi/shell/command/\_CommandProviderMixin> and epi/shell/command/\_CommandConsumerMixin classes provide the link between the commands source and where they should be displayed. The provider has a list of commands and the consumer has a list of command providers and displays the commands for those providers.