Marionette Views

MarionetteJS

I have been working with Backbone for a while now and have bumped into Marionette a number of times - every time I have pondered to myself about implementing it into the project I was working on at the time.

"Oooo, this looks good - we should try it."

At first the thought of adding something new to the project was scary and daunting. The ideas of adding additonal weight to the application and increasing the learning curve were at the top of the list.

Then I had the "Ahah!" moment - the things Marionette are providing are all the things you write anyway, albeit probably named differently. There are 2 very important types of data that Backbone provides:

  • Models
  • Collections

We know that a model represents a single item and collections contain many models. Naturally, the way in which we display data is very much the same - good examples are things like <ul>, <li>, <table> and <tr>.

Lets have a look

Lets take a look at an example of how we would implement a table using Backbone and a number of common practises.

Table Template

The table will show a collection of people.

<table>
    <thead>
        <tr>
            <td>Name</td>
            <td>Age</td>
        </tr>
    </thead>
    <tbody>
        <!-- ROWS HERE -->
    </tbody>
</table>

Table View

The table view will render the template and a view for each model in the collection given to it.

var TableView = Backbone.View.extend({
    template: JST['table'],
    renderOne: function (model) {
        var view = new RowView({ model: model });
        this.$('tbody').append(view.render().el);
    },
    render: function () {
        this.$el.html(this.template());
        this.collection.each(this.renderOne, this);
        return this;
    }
});

Row Template

The row will show a model of a person.

<tr>
    <td><%= name %></td>
    <td><%= age %></td>
</tr>

Row View

The row view will render the template for the model given to it.

var RowView = Backbone.View.extend({
    template: JST['row'],
    render: function () {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

Putting it together

Now we have the basic building blocks we can render a table onto the page giving it any collection data we want.

var peopleView = new TableView({
    collection: new Backbone.Collection([
        { name: 'Joe Bloggs', age: '33' },
        { name: 'Jane Bloggs', age: '31' }
    ])
});

$('body').html(peopleView.render().el);

This should all look fairly familiar if you have used Backbone. You will also know that you end up writing this same kind of thing ALOT. Most of us will abstract this kind of logic into specific views, base models etc.

This is where Marionette woke me up, we have models and collections for data - why not move the same type of concepts to how we organise and put together our views. Lets try the same thing, but with Marionette.

Marionette time

For the sake of saving time and characters - we will keep the templates being used exactly the same as before. This is something you can most likely do with existing projects as well, making switching easier.

Table View

Marionette removes all of the boilerplate code and the same task becomes a matter of configuration rather than copy/paste. It also becomes very descriptive and repeatable - which is always a plus in large teams and codebases.

var TableView = Marionette.CompositeView.extend({
    template: JST['table'],
    childView: RowView,
    childViewContainer: 'tbody'
});

Row View

Again, all that boilerplate is gone. A thing to remember here is that by default Marionette will pass the result of the models toJSON() method to the template. Giving us a standard pathway for template data.

var RowView = Marionette.ItemView.extend({
    template: JST['row']
});

That's it

The resultant code has been reduced, a standard approach has been put in place and much of the existing code can be kept, such as the higher level rendering and the templates.

Another benefit is that Marionette has also registered all the relevant listeners to the model and collection, meaning that it will automatically re-render when any change occurs - and it will happen in the most efficient way.

Needless to say, implementing Marionette into an existing project is not as destructive as I first thought. There are many other beneficial objects Marionette provides such as Application, Controller and CollectionView to name but a few.

Hopefully this helps enlighten you to the benefits, the potential to write less code, follow a number of best practises and make things more understandable along the way.