Command Pattern v2 using Knockout

Update: this feature is now available as part of the ko.plus library available on GitHub and NuGet!


In an earlier post I outlined a basic implementation of a command pattern using Knockout that tracks the progress of an asynchronous operation using the jQuery.Deferred object.

Having used it for a couple of weeks I found that there were a few things that could do with improving, so here we go with Command v2!.

No more .execute()

The first version of the command would wrap the operation in an object, meaning that whenever you wanted to bind to or just run the action you had to call a .execute method on the new object:

//old code
var viewModel = {
    doSomething: new Command(function() {
        //invoke async operation        
    });
};

//invoke the command
viewModel.doSomething.execute();​

Whilst using the command I kept forgetting to add the .execute (particularly to bindings) and this quickly became annoying, so I changed the constructor function to return the execution function instead of a new object in a similar manner to ko.observable.

Note: having previously been returning this I had to ditch the traditional constructor for a factory method that is a bit more in line with the Knockout syntax.

ko.command = Utils.command = function (options) {
    //...

    //execute function (and return object
    var _execute = function () {
       //...
    },
    
    //public properties now attached to _execute instead of this
    _execute.isRunning            = _isRunning;
    _execute.done                 = _done;
    _execute.fail                 = _fail;
    _execute.always               = _always;

    return _execute;
};

After these changes the invocation of the command is much simpler:

var viewModel = {
    doSomething: ko.command(function() {
        //invoke async operation 
    });
};

//invoke the command
viewModel.doSomething();

//get the status of the operation
viewModel.doSomething.isRunning(); 

//attach a success handler
viewModel.doSomething.done(function() {
    alert("Finished");
});​

That’s much cleaner, and the helper observables and functions such as isRunning and the callback methods still function as before.

Support for canExecute

The command pattern implementation in .NET (the original inspiration for writing this) includes a CanExecute method that determines whether or not the command is currently in a suitable state to execute. For example, if the command is going to submit a form, the CanExecute implementation might check that the form is valid prior to submission.

For my JavaScript command I wanted to be able to specify a custom function to determine whether or not the command can execute, as well as always preventing execution whilst the command is running asynchronously. To do this I made use of Knockout’s computed observables to implement a canExecute property:

ko.command = Utils.command = function (options) {
    //factory method to create a $.Deferred that is already completed
    _instantDeferred = function(resolve, returnValue) {
       //
    },

    //execute function
    var _execute = function () {
        //check if we are able to execute
        if (!_canExecute()) {
            //dont attach any global handlers
            return _instantDeferred(false).promise();
        }

        //...
    },
    
    //dummy to allow us to force a re-evaluation of the computed _canExecute observable
    _forceRefreshCanExecute = ko.observable(), 

    //canExecute flag observable
    _canExecute = ko.computed(function() {
        _forceRefreshCanExecute(); //get and ignore the value

        //can execute if we're not running, and either there's no canExecute
        //function specified or it returns true
        return !_isRunning() &&
            (typeof options.canExecute === "undefined" ||
            options.canExecute.call(_execute));
    }, _execute),
    
    //invalidate canExecute
    _canExecuteHasMutated = function() {
        _forceRefreshCanExecute.notifySubscribers();
    };

    //public properties
    _execute.canExecute           = _canExecute;
    _execute.canExecuteHasMutated = _canExecuteHasMutated;

    return _execute;
};

Things of interest here:

  • If the _execute method cannot execute, it returns a $.Deferred object that has already been rejected so that any calling class that attaches a done/fail handler will not throw exceptions and can at least sensibly react
  • We are creating a dummy observable (_forceRefreshCanExecute) that is used by the canExecuteHasMutated function to force the computed canExecute observable to refresh (as described here)

Synchronous Execution

The first version relied on the action returning a promise object representing the status of the background operation, but after implementing the canExecute support I started to see a use case for commands that do not do anything in the background and simply execute synchronously.

var ExampleViewModel = function(externalValidationDefinition) {
    var _self = this;
    this.listOfItems = ko.observableArray();
    this.clearList = ko.command({
        action: function() {
            _self.listOfItems.removeAll();
        },
        canExecute: function() {
            return _self.listOfItems().length > 0;
        }
    });
};

To accommodate this type of usage I have updated the behaviour of the command so that when the action returns anything other than a promise it wraps that result in an immediately-completed jQuery.Deferred instance and then executes any registered handlers.

Other Minor Changes

errorMessage Removed

I realised that the error handling in version 1 was far too dependent on the signature of the error handler – what works for a failed AJAX request will not work for a failed HTML5 SQL request etc. – so I elected to remove the built-in error message recording and leave that down to the user.

Better Error Handling

As part of the support for synchronous code I also added improved error handling so that any error thrown directly from the action will be passed to the fail handlers.

Source

As ever, the code and unit tests are available on GitHub so help yourselves.

Advertisements

9 thoughts on “Command Pattern v2 using Knockout

  1. alexmaie says:

    Hi,

    I am trying to use your command pattern implementation in a project of mine. How would i actually bind the command? something like : ?

    • You can bind it directly to the click handler. If your command is called “doSomething” then you bind it using:

      data-bind="click: doSomething"

      There are plenty of examples in the jsFiddle links in the post

  2. Hi Steve.

    The two articles here is the business. Nobody really does cmd-patters in js ? 🙂

    My situation is piratically identical to the one described in the first article, except we are doing a game on top of all the “boring” logic, which lead me to believe the command-pattern would be a good fit, to handle all-sorts and clean everything up. Before i found your article i was digging into promises already, why this looks very promising at first glance. I hope you don’t mind a couple of questions, on top of all my ramblings 🙂

    Have you had any buggish experiences using jQuerry.Deffered? I came across at least two unrelated negative comments, with strong suggestions of going for a 3rd party lib.

    Also, I’m loading two-three modules, where I also expected to use commands rather than monoliths. It’s a game so we need preloading, and mechanisms for limiting server requests. I know it’s not much to go by, but would appreciate your thoughts(?).

    Thanks for sharing goodies and details.

    Regards,

    Peter,

    • Hi Peter,

      Glad you liked the articles!

      I have used jQuery.Deferred in many applications and libraries and have never had any problems with it. If you do find any bugs there is obviously a huge community around jQuery as well so there shouldn’t be a problem getting them fixed. What were the negative comments, out of interest?

      Without knowing more details of your game I couldn’t really say how appropriate the command pattern would be, but given that it is an abstraction of a fairly simple concept I would imagine there would be a use for it. The library is available at http://github.com/stevegreatrex/ko.plus so feel free to grab whatever part of the source makes sense for you.

      Steve

      • Peter Lindhard says:

        After commenting i dived slightly deeper, and now understand it to be due to a previous slightly non-conform implementation, which is now deprecated looking at the jQuery API as of 1.8.3. This concern was pushed by two contributors to more conform libraries, which now seem biased to me – Q and another which i forgot. The other were claims of the “error:”- promise behaving unexpectedly in customized situations, which was my real concern. My experience and “research” is limited to half a day of google/stack* and experiments… so i took the chance and asked, guessing you would have had this in play for some time 🙂

        Coming from Java and C# with limited experience there I’m finding pattern implementations as dynamic as the language… so cudos for making something this elegant and thanks again!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s