Skip to content Skip to sidebar Skip to footer

How Do I Pass References Of Views/models To Other Views/models/routes In Backbone.js

So I'm really new to backbone.js and I'm trying to understand the basic concept when it comes to getting parts(views/models/routes) to interact with other parts. Here's an example.

Solution 1:

First, you need to understand the role of each Backbone classes. Reading on MVC first might help.

Model

The model isn't necessary when rendering a view. Its role is to handle the data, which can be local, or from an API. All the functions that affect the data should be in the model, and a model shouldn't have anything related to rendering.

There are always exception, where you could use a model to handle data related only to rendering, but you'll know when you find such case.

A simple example is a book:

// The Book model class
var Book = Backbone.Model.extend({ 
    idAttribute: 'code',
    urlRoot: '/api/book'
});

// a Book instance
var solaris = new Book({ code: "1083-lem-solaris" });

Fetching from an API would call:

// GET http://example.com/api/book/1083-lem-solaris
solaris.fetch(); // this is async

When fetching, the API returns the JSON encoded data.

{
    "code": "1083-lem-solaris",
    "title": "Test title",
}

The attributes are merged with the existing attributes, adding the ones that are not there yet, and overwriting the values of the ones already there.

Collection

A collection's role is to manage an array of models, which, again, can be local or fetched from an API. It should contain only functions related to managing the collection.

var Library = Backbone.Collection.extend({
  model: Book,
  url: '/api/book'
});

var myLibrary = new Library();

// just adds an existing book to our array
myLibrary.add(solaris);

You can fetch a collection to get an array of existing books from an API:

myLibrary.fetch();

The API should return:

[
    { "code": "blah-code-123", "title": "Test title" }, 
    { "code": "other-code-321", "title": "Other book title" } 
]

Using the collection to create a new book and sync with the API:

var myNewBook = myLibrary.create({ title: "my new book" });

This will send a POST request with the attributes and the API should return:

{ "code": "new-code-123", "title": "my new book" }, 

View

The view handles its root DOM element. It should handle events from its DOM. It's best used to wrap small component and build bigger components from smaller components.

Put links directly in the templates, in the href of an anchor tag. There's no need to use events for that.

<a href="#my-route">link</a>`

Here's how I render (simplified) a list.

// book list item
var BookView = Backbone.View.extend({
    tagName: 'li',
    template: _.template('<a href="#book/<%= code %>"><%= title %></a>'),
    initialize: function() {
        // when the model is removed from the collection, remove the view.
        this.listenTo(this.model, 'remove', this.remove);
    },
    render: function() {
        this.$el.empty().append(this.template(this.model.toJSON()));
        return this;
    }
});

// book list
var LibraryView = Backbone.View.extend({
    template: '<button type="button" class="lib-button">button</button><ul class="list"></ul>',
    events: {
        'click .lib-button': 'onLibButtonClick'
    },

    initialize: function(options) {

        this.listenTo(this.collection, 'add', this.renderBook);
    },

    render: function() {
        // this is a little more optimised than 'html()'
        this.$el.empty().append(this.template);

        // caching the list ul jQuery object
        this.$list = this.$('.list');

        this.collection.each(this.renderBook, this);

        return this; // Chaining view calls, good convention http://backbonejs.org/#View-render
    },

    addItem: function(model) {
        // Passing the model to the Book view
        var view = new BookView({
            model: model
        });
        this.$list.append(view.render().el);
    },

    onLibButtonClick: function() {
        // whatever
    }

});

Router

The router handle routes and should be as simple as possible to avoid it getting too big too fast. It can fetch collections and models, or the view can handle that, it's a matter of pattern at that point.

var LibraryRouter = Backbone.Router.extend({
    routes: {
        '*index': 'index',
        'book/:code': 'bookRoute',
    },

    index: function() {
        var library = new LibraryView({
            el: 'body',
            // hard-coded collection as a simple example
            collection: new Library([
                { "code": "blah-code-123", "title": "Test title" }, 
                { "code": "other-code-321", "title": "Other book title" } 
            ])
        });
        library.render();
    },
    bookRoute: function(code) {
        var model = new Book({ code: code });
        // here, I assume an API is available and I fetch the data
        model.fetch({
            success: function() {
                var view = new BookPageView({
                    el: 'body',
                    model: model
                });
                view.render();
            }
        });
    }
});

Events

Everything in Backbone has the Events mixin, even the global Backbone object. So every class can use listenTo to bind callbacks to events.


It would be very long to go in depth for everything in Backbone, so ask questions and I'll try to extend my answer.


Post a Comment for "How Do I Pass References Of Views/models To Other Views/models/routes In Backbone.js"