Tuesday, May 26, 2009
Javascript, as I'm sure you are aware, has no in-built knowledge of classes, inheritance or interfaces as other OO programming languages do.  We have to engineer these using various constructs and work-arounds, in order that we maintain code order and good programming principles.  With more and more code on the client-side in order to provide rich user experiences, this is vital or you'll be condemned to snippet hell. 

Simple View-Controller pattern

Say you want to implement a bog-standard separation of View-Controller logic.  The View is a collection of controls, and directly handles the interaction of these controls before packaging them up and sending them on to the Controller.  In the Windows world, we would raise a custom event from the View which the Controller hooks into, but given Javascript's flexible duck-typing, we can bind the View directly to the Controller and inject a Stub in the future for testing if we should wish.

Anyway, our View has a button.  When the user clicks the button, we want the Controller to know what to do, not the View. 

The View will have a SetController method, which when set, will bind the button's click event (I've omitted the unbind to clear things up) to the appropriate method on the Controller.

Like so:

function RefineSearchView() {
    var _controller;
}

RefineSearchView.prototype.setRefineSearchController = function(newController) {
    this._controller = newController;
    $("#btnStreetRefineFilter").bind("click", createMethodReference(this._controller, "HandleFilter"));
}

NOTE: this is where it gets interesting.  createMethodReference() - what's that all about?  Why don't I just do:

$("#btnStreetRefineFilter").bind("click", this._controller.HandleFilter);

You could expect this to simply bind the click event on to this particular View's Controller's HandleFilter() method.  Non?

Non.  The reason this won't work is because when we bind the click event, we are not in the correct context.  This article - with the suitably majestic title of Object-Oriented Event Listening through Partial Application in JavaScript - will explain it in ways far better than I could!

This is to demonstrate in it's most basic format - we can go on as the article suggests, wave our magic refactoring wand until it transforms from the ugly duckling of createMethodReference into the elegant swan of

this.element.onclick = this.buttonClicked.bind(this);



Controller Handle method

Now we have this set up, it's just a case of implementing our HandleFilter method on the controller:


RefineSearchController.prototype.HandleFilter = function(e) {
    var searchParams = this._searchController.getSearchParams();
    var locality = this._view.getLocality();
    var town = this._view.getTown();

    searchParams._locality = locality;
    searchParams._town = town;

    this._searchController.setSearchParams(searchParams);
    this._searchController.search();

    this._view.updateFilterStatus(searchParams);
}

So now we have completely separated our code into View and Logic sections.  This example was a bit contrived, but you can imagine the situation where our View has to gather information from a number of controls before wrapping these up and sending them on to the Controller in a nice abstract package, similar to the searchParams outlined above.

Not only does this approach give benefits in terms of maintenance, but the stage is now set for unit-testing and programmatically driving your dynamic web page...

Tuesday, May 26, 2009 10:04:57 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Javascript | Patterns | TDD#
Wednesday, May 20, 2009
Okay, so this is hardly a ground-breaking topic.  But I think it's a valid showcase as to how rich, UI experiences can be delivered via the browser without costing the earth.

Picture the scene - I have a web page with a jquery Grid (FlexiGrid - though I think I will be upgrading to jqGrid due to it's continued developer support - but more on this later) and a toolbar (a very cool Vista style toolbar).

One of the commands available on this toolbar is Print. 

When the user clicks this command, a jquery UI dialog pops up, displaying a selection of valid reports which the user may select.

This reports list is generated from the server.

So, if all of this was to be done as the page loads - well, you can imagine the performance would be unacceptable.  But I want to keep the user experience rich - I don't want them navigating from the grid to another page when they click Print.  So I need to do this using AJAX.

The process is as follows:

 




The Print Button Handler calls the PrintWebService via an AJAX call using some jquery magic as so:

 $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                data: "{}",
                dataType: "json",
                url: "http://localhost/PrintService/PrintService.asmx/RenderPrintDialog",

                success: function(data) {
                    $("#printdialoginner").html(data.d);
                    $("#printdialog").dialog("open");
                },

                error: function(xhr, status, errorThrown) {
                    alert(status);
                    alert(errorThrown);
                }
            });

Inside the service, we can get our reports from the server (from the database) at our leisure.  Ish.

Now comes the clever part.  To return the UI, all we're doing is churning back some HTML, right?  But what if we want to be able to visually SEE what we are going to return, at design-time? 

Thanks to Scott Gu, we can get full VS designer support when creating our dynamic UI - check it out - http://weblogs.asp.net/scottgu/archive/2006/10/22/Tip_2F00_Trick_3A00_-Cool-UI-Templating-Technique-to-use-with-ASP.NET-AJAX-for-non_2D00_UpdatePanel-scenarios.aspx

So we create our .ascx controls as normal, pass the path to the ViewManager, and let it get it's hands dirty.  It also keeps a nice, clean MVC separation.

Using this trick, I've been able to deliver a seamless, rich UI without having noticeable effects for the user.  Okay, so there is a slight delay when they bring up the Print dialog for the first time (I know, I've not mentioned caching here but do I need to?) but it's barely noticeable.










Wednesday, May 20, 2009 7:57:56 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Javascript | Patterns | Web Design#
Wednesday, May 13, 2009
We had a review of some client-side code today, as it had started to smell a little "off".

As always, the indication I use when quickly reviewing a design is - how easy is this to unit test?


The problem

Logic all over the place.  Massive "if" statements.  More spaghetti than an episode of the Sopranos.

For our web app, we have a number of "tools"; when the user clicks one, it puts the application into that particular tool mode, which means that any subsequent mouse events have to check which mode we are currently in, and take the appropriate action.  Not only that, but we have introduced a vector view layer (SVG) so we have some tools that update the image layer, some that update the vector layer, and some that update both.

The solution

Stick to established patterns.  When dealing with UI, everything boils down to MVC in the end.


 

What we've done here is separate out each tool into an "Interactor" class.  The View provides the abstraction of each view type, and also the UI events.  The Controller provides the glue to stick everything together.

In Summary:

  • The View knows about the different view types, and knows about UI events.
  • The View Types know how to render themselves, but are still pretty "dumb".
  • The Controller knows about UI events, and things called Interactors, but it doesn't know what Interactors are or what they actually do.
  • The Interactors know exactly what is going on, they interact directly with the view type and the server.





This solution certainly isn't "pure" by any means - there is no M!  And I am in no doubt that we could refine this further. 

But the main thing is we have separated everything out into distinct, logical components that have a defined and related set of responsibilities.

What's more this design is geared for unit testing.  We can test the Interactors independently of the views (by dependency injection, which we will do later) and then add another layer of tests integrating the Controller, and so on.



Wednesday, May 13, 2009 8:16:28 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Patterns | TDD | Javascript#
Search
Archive
Links
Categories
Admin Login
Sign In
Blogroll