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 patternSay 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 methodNow 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...