RK* - rikkertkoppes.com

thoughts

Command manager

Building a JavaScript heavy front end application? Are you defining actions that are called from various places in the application? As a part of another action or as a response to events? Here is a command system to the rescue.

Defining Commands

Defining commands is easy, just define a function (or class method for that matter) and pass it with a name to the register static. For clarity throughout this article, I will also import the Command class.

var Command = com.rikkertkoppes.util.Command;

function foo(a,b,c) {
  console.log('foo',a,b,c);
}

Command.register('foo',foo);

Now you might be concerned about the scope your method will be executed in. Therefore, the register static takes a third parameter for the execution scope. This defaults to window.

Invoking commands

There are three ways to execute a command, all of which are roughly the same:

  1. Command.doCommand('foo arg1 arg2 arg3');
  2. Command('foo')(arg1,arg2,arg3);
  3. Command().foo(arg1,arg2,arg3);

The first method, via the doCommand static takes one string. This string will be split by whitespace. The first piece will be taken as a command name and the other pieces are passed as arguments. This is useful for setting up a command line interface for testing purposes or for receiving messages from the server.

The second method passes a command name to the Command object. When calling the Command object like that, it will return the command, in the correct scope. This command can then be executed. Optionally, a second scope parameter can be passed to the Command object, this will override any previously set scope.

The third method calls the Command object without any parameters. This will return an object literal containing all commands in their correct scope. These can then be executed as well. These second and third options can also be used to retrieve function references to be used as event handlers. For instance:

document.body.addEventListener('click',Command('foo'));

Command mapping

In practice, mostly when working with event handlers, the arguments the event returns hardly ever line up with the arguments your command expects. This can be resolved by defining mapping methods. A map will be doing the rewriting of arguments.

foo.maps = {
  event: function(e) {
    return ['click: ',e.clientX,e.clientY];
  }
};

window.addEventListener('click',Command.map('foo').event,false);

Notice that a maps object literal is added to the command method. This property contains any number of mapping functions that take the arguments given by the event handler and returns an array of arguments that will be passed to the command method. In this example, an ordinary event object is passed in and the mouse positions are returned. With this information, the command method is called.

Also notice that the method that will be added as an event listener is somewhat different. By calling the map static, a map object is returned, which is built from the original maps property you defined. This map object contains (new) method references that can be assigned as handlers.

Enabling and disabling commands

In certain cases you want to make it impossible for commands to be executed. When commands are hooked up to several interface elements (eg buttons and keyboard shortcuts), this is best done in a central place, hence:

  • Command.disable('foo')
  • Command.enable('foo')

Attaching events

Since I wanted to make this command manager framework agnostic, it does not fire custom events. However, I added the following abstract static methods that you can implement yourself:

  • Command.onCommandEnable(name)
  • Command.onCommandDisable(name)
  • Command.onCommandExecute(name)

You can either put a bunch of code in these methods, or fire a custom event that other parts can listen to. If either of these implemented methods return false, the associated default action will not be executed.

Commands and use cases

Commands are designed to be the JavaScript analogue to use cases. These are the things that your application should do. One use cases could for example be "create a blogpost". For creating a blogpost, some user input data is needed, an email address and a post body, say. This data, and only this data, is the input for the command. The command should handle the rest.

Commands in a controller

Basically, a controller is the thing that responds to events and updates the view with information from a model. In the very basic sense, events are "things that happen". For server side controllers, events are usually http requests. For JavaScript controllers, events are DOM or custom events.

The most basic view in a JavaScript application is the DOM and its associated rendering on screen itself. More advanced applications use more elaborate components like dialogs, tab panels etc. These are also generally known as "widgets". These widgets can often fire custom events to which the controller can respond.

A model in the most basic sense is just a variable, but this can be expanded to complete object oriented structure. A (very) basic example of a MVC setup is the following:

//model
var message = 'Hello World';

//controller logic
// respond to event
window.onclick = function() {
  //update the view
  document.body.innerHTML = message;
}

When you have a lot of events and a lot of actions to do, some tidying up is needed. Usually, one already extracts methods that are used often. This is where commands come into play.

//model
var message = 'Hello World';

var controller = {}
controller.init = function() {
  Command.register('hw',controller.hw,document.body);
  window.addEventListener('click',Command('hw'),false);
}

controller.hw = function() {
  document.body.innerHTML = message;
}

Get it

Additional resources (top 15)

Below is a list of additional resources that might contain extra information about the subject at hand. These are all sites linking to this one (i.e. backtracking).

  1. command manager commands - Google Search (1)

comment

giocate al casinò online (2010-03-29)

The command manager is a named collection of command profiles. Each profile is an object of the CExtCmdProfile class and has its own unique name and keeps a list of HWND handles. This allows any window of the application to "know" which profile it belongs to. Although the command manager features multiple profile support, in most cases, applications are based on a single profile. Great article.Thanks for it...

Add comment
older articles

AdministrationAtom feed