You're viewing a post from the archive. Don't forget to checkout our latest post HTML5-powered Ajax file uploads

A little while back, I posted about Sammy.js and how it had simplified the way I was designing client side applications. In the meantime, my usage has grown to the point where I need a bit more structure, in a similar way to how an application originally built in Sinatra may at some point be moved to Rails to take advantage of some of the conventions there.

With this in mind, I have been looking for something to represent the 'Model' aspect of my application to abstract some of the Ajax requests. What I found last week was Kiwi.js which aims to provide the m the v and the c for the client-side world. I have spent some time this weekend investigating Kiwi, and really like the way it works (see appendix).

However, in doing so I found myself comparing it to Sammy.js. There are obviously differences between them, and there are parts of Sammy I like better (routing), and parts of Kiwi I like better (MVC structure, view handling and models). I have therefore put together some thoughts about how the best elements of both frameworks can be combined to create an awesome hybrid.

The main thing I really wanted was for it to implement routes in a similar way to Sammy. Specifically I want to detach the triggering of controller actions from specific views.

If I create a link which is intended to trigger a change in state (such as showing a form), I don't necessarily want this link to be attached to any particular view. This gives me the freedom to move it around on the page without worrying about its view context. Only subscribed events need to be scoped to views. The way that Sammy helps in this area is that it has the concept of routes to handle listening for events anywhere.

This last point leads me to think that routing could be used for triggering controller actions, rather than tying them into specific behaviour on DOM elements.

instead of having:


$v('PeopleForm', {
  listeners: {
    'a#new_link click': 'PeopleController.new'
  }
});

You would define something like this in the routes section of your application:


  $r.get('#/people/new', 'PeopleController.new')

And then any link in your view that looks like this would trigger the action:


<a href="#/people/new"> Add a person</a>

This also makes it easier to handle forms:


<form action="#/people" method="post">

One of the benefits of doing it in this way is that controllers can gain the concept of parameters. At the moment, Kiwi controllers have to go looking inside the calling view for the parameters to use for RESTful Ajax requests, eg:


'create' : function(){
    var data = {
      'person[name]': $('#person_name', this.view.node).val(),
      'person[login]': $('#person_login', this.view.node).val(),
      'person[email]': $('#person_email', this.view.node).val()
    }
    $m.Person.create(data, this.publish)
  }

Whereas, in the Sammy world, this action would be far more likely to look like this:


'create' : function(){
  $m.Person.create(params, this.publish)
}

where params are the serialised attributes of the form which was submitted, or alternatively part of the URL submitted by a link. Eg, in Kiwi, you would have something like this:


  'delete' : function(){
    var models = this.data
    $m.MyModel.find(data[0].id).destroy(this.publish)
  },

If Kiwi had Sammy's routes, we would do something like:


  $r.delete('#/people/:id', 'PeopleController.delete');

combined with an action such as:


  'delete' : function(){
    $m.MyModel.find(params['id']).destroy(this.publish)
   }

I think Kiwi views are really powerful, and I love the way they subscribe to controller actions to listen for changes. However, most of the emphasis seems to be on attaching listeners to views to trigger controller actions, rather than subscribing to actions. Hence, having to do the following makes it seem like subscribing to multiple actions was an oversight:


people_list = $v.PeopleList.initialize($("#people_list"));
people_list.subscribe_to('PeopleController.create');

I would love to be able to do the following:


$v('PeopleList', {

  subscribe_to: {
    'PeopleController.create': 'my_create_callback',
    'PeopleController.delete': 'my_delete_callback'
  },

  my_create_callback: function(action_name, request){
    // add something into my list
  },

  my_delete_callback: function(action_name, request){
    // remove something from my list
  }

});

In terms of making subscriptions more readily available to multiple views, it might also be nice to have some 'global' view widgets - such as flash notices, which listen to all actions and act according to some special rules.

Eg:


$v.Flash.initialize($("#flash_notice"));

'create' : function(){
  flash_success = "New person created"
  flash_failure = "Failed to add person"
  $m.Person.create(params, this.publish)
}

In any case, I am really excited by these developments, and think that cross-pollination of ideas is going to achieve some great things. Over the last few years the popularity of various server-side frameworks has led to vast improvements in their design. However, the 'view' part of most of these frameworks is often treated as an after-thought, and efforts are made to hide 'ugly' view code beneath a veneer of 'nice' server code (eg: HAML).

There seems to be a shift at the moment towards appreciating the complexity of developing client-side code, and giving developers in that area the same kind of tools and organisation which many developers have been enjoying on the server-side for several years now.