Archive for March, 2007

Binding to Views

Monday, March 26th, 2007

I’ve landed on something of a simplified View object that can be used for javascript widgetry. The notion really is that the views are just some template
html string that gets plopped onto a page and bound to a model and a controller. This implementation takes that pretty literally. The View expects a model, controller, peer element (where it should ‘paint’ its template), Template, and Binders. Subclasses should just pass the right thing to the View constructor. The TaskView became quite simple when it switched to using the base View:

var TaskView = function(_task, _viewPort){
	View.call(this, {
             model:_task,
             controller:this,
             peer:_viewPort,
             template:TaskView.Template,
             binders:TaskView.Binders
        });
}
TaskView.extend(View);
TaskView.Template = '<input type="checkbox"/><span></span>';
TaskView.Binders = [
	new ModelBinder(new TagNameLocator('input',0), 'checked', '_complete'),
	new ModelBinder(new TagNameLocator('span', 0), 'innerHTML', '_description'),
	new EventBinder(new TagNameLocator('input', 0), 'click', '_handleCheckboxClicked')
];
TaskView.methods({
	_handleCheckboxClicked: function(event){
		if(event.target.checked){
			this.getModel().complete();
		}
	}
});

What’s going on here? The TaskView constructor just calls the super class constructor with the params it wants: model, controller, peer element, template, and binders. Thats a lot of args, and we may be able to help that with some good conventions. But what are all the args for?

  • The model is the data that the view will display.
  • The controller is meant to handle the behavior of the view. User gestures (mouse clicks and such) are ‘bound’ to methods on the controller via EventBinders.
  • The peer is the html element the view should “paint” into.
  • The Template is..well…the “template” or “mock” markup for the view.
  • The binders are what bind behavior and data to the view. ModelBinders are for binding bits of the model to bits of the view. EventBinders are for binding user gestures (html events) to methods on the controller.

OK, but how does it get put together? The View constructor will set the innerHTML of the peer element to the value of Template and then iterate over the binders telling them to ‘bind’ to the peer. Binders use Locators to find the html elements to bind to. The TagNameLocator will find elements with a particular tagName. Optionally, it will take an index which would make the locator only return the N-th element with that tagName where N is the index provided.

So, in the TaskView, there are 2 ModelBinders and 1 EventBinder. The first ModelBinder binds the ‘checked’ attribute of the first ‘input’ element to the ‘_complete’ property of the model. The second ModelBinder binds the ‘innerHTML’ attribute to the ‘_description’ property of the model. In both cases, the Binder creates a ModelBinding object which becomes an observer of the model and will keep the model and html element in sync. The EventBinder binds a ‘click’ event on the first input to the “_handleCheckBoxClicked” method on the TaskView (which is serving as the controller here).

Not too bad I’d say. Needs some work still though. My first thought is to
take the template and binders out of the call to the super constructor and make them smart defaults. If the super class constructor doesn’t have them in the call, it can look on the subclass for a ’static’ Template and Binders fields. Another thing I’d like to do is have the ModelBinder support methods as well as properties, so it could bind the return value of a method (that way we can bind to ‘getDescription’ instead of ‘_description’).

Maybe tomorrow.

Views Clearing Up

Saturday, March 17th, 2007

Made some more progress on the TaskList widget. Sure feels like I got off on the wrong foot or something…its been changing a lot. I guess its really just been cleaning up more than really changing. At any rate it is moving along and I’m starting to get a clearer picture of what the views are supposed to be doing and how contained they really can be. Today’s progress was made in the TaskListView2_UT.html.

I’m thinking about heading in a Template direction with it next. I really don’t like the idea of locking up all the markup into javascript dom element creation. Templates are much easier to read and easier to modify. The template work should start in TaskListView3_UT.html.

Smaller Steps or Less Wine

Saturday, March 17th, 2007

“They” say that you should take small steps when refactoring. Super small steps at first. Then as you become more comfortable with the pace and are more confident in your ability to do specific refactorings, you tend to start taking bigger steps. And if you have some trouble…back off the changes and take smaller steps. I was doing a refactoring last night and I took too big of a step. It took me an hour to finally back off and take smaller steps. I was SO confident in the code I’d written that I was refusing to accept it was flawed. Once I backed off it took one test to find the culprit:

$A = function(){
	var arr = new Array();
	for(var i=0;i<arguments.length;i++){
		var currArr = arguments[i];
		for(var j=0;j<currArr.length;j++){
			arr[i+j] = currArr[j];
		}
	}
	return arr;
}

That logic (problem part colored in red) made perfect sense to me…in my defense I was on my third glass of wine ;)

This is basically prototype’s function that ‘casts’ the provided object to an array. This one supports passing multiple iterable objects (any object with a length property whose members are index-accessible) and it will effectively concatenate them. There is a concat method on an array object, and I’d love to just use that, but you can’t pass the ‘arguments’ variable to the array ‘concat’ method…and that is what I needed to do.) I could have just used prototype. I really like some of what prototype provides, but (I’m sure this has been said before) I don’t want to pull the whole thing in just for a few of the functions I like. Some folks have the same issue with open source java code, but that isn’t as big an issue to me as the javascript one…anyway that’s another post.

Moral of this story: take smaller steps or drink less wine ;)

Not the Simplest Thing

Thursday, March 15th, 2007

I realized last night I’m probably not *REALLY* doing the “Simplest thing that could possibly work” with this Test First Javascript Widget. If you’re nodding your head thinking “Umm…yeah, you could do that with like 2 lines of javascript” you’re right. With the simple requirements I listed, you could accomplish the TaskList with and input and a button with an onclick that adds a row to a table with a checkbox. Obviously I’m diggin for more depth in the implementation.

Perhaps its because I’m the customer? I know i’m going to eventually need to persist these tasks, and potentially need to handle a back button. I also (since i also have the customer hat here) know that I’m wanting to support nested sub-tasks. When a parent task is completed, all of its child tasks are marked completed as well…and when all child tasks are completed, then the parent task is automatically marked as complete. If only part of the sub-tasks have been completed, then the parent task is put in a ‘partially completed’ or ‘in progress’ state.

So really I’m coding for more requirements than I’ve let known. I’m not sure if that’s being fair to the process…but its and experiment.

I had a little time to kill tonight so I knocked out some refactorings that I was itching to do. Check them out on the TaskListView test page. (The stuff I did today is about half-way down…I dropped in an HR and today’s date…probably should have just started a new Test file).

Test First Javascript

Sunday, March 11th, 2007

I want to try an experiment. My goal it is to demonstrate how good OO principles and patterns can be applied when solving a problem with javascript. To achieve this goal, I’m going to develop a custom javascript component Test First and try and document the process as I go. I’m hoping this will also help me with some ideas I’m struggling with in the javascript component arena.

The component is a Task List. The first set of requirements are:
The user can add tasks to a list
Tasks are just a short description of what is to be done
The tasks can be marked as complete

The tasks won’t be persisted right now. It will just be in the browser. I know thats not a lot…but I’m the user and I can clarify as we go ;). Each page in this experiment is a JS Unit test page. I’m gonna do my best to communicate what the thought process is for each test and for each refactoring. The ‘thoughts’ will be followed by the test code and then the Task List code that made the test pass. Changes are in red. The test code background is blu-ish…and the code background is gray.

I’ll post more blog entries as the component progresses. You can follow the progress of the tests here. Each test page will link to the next at the bottom. At the top of each test page is a link to open the jsunit test runner for the page.