Search code examples
backbone.jsbackbone-routing

Routing & events - backboneJS


How should I be handling routing in BackboneJS? When routing, after new-upping my view, should I be triggering an event, or rendering the view directly?

Here are the two scenarios:

Trigger Event:

routes: {
    'orders/view/:orderId' : 'viewOrder'
},
viewOrder: function (orderId) {
    var viewOrderView = new ViewOrderView();
    vent.trigger('order:show', orderId);
}

In my view, I have:

var ViewOrderView = Backbone.View.extend({
    el: "#page",
    initialize: function () {
        vent.on('order:show', this.show, this);
    },
    show: function (id) {
        this.id = id;
        this.render();
    },
    render: function () {
        var template = viewOrderTemplate({ id: this.id });
        this.$el.html(template);
        return this;
    }
});

OR, should I go this route:

routes: {
    'orders/view/:orderId' : 'viewOrder'
},
viewOrder: function (orderId) {
    var viewOrderView = new ViewOrderView({id : orderId });
    viewOrderView.render();
}

In my view, I have:

var ViewOrderView = Backbone.View.extend({
    el: "#page",
    initialize: function () {
        //init code here
    },
    render: function () {
        var template = viewOrderTemplate({ id : this.id});
        this.$el.html(template);
        return this;
    }
});

I think it's the first scenario - given that backbone is event driven, but the 2nd obviously has less code.

Also, I suppose a third scenario would be to keep the view code in the first scenario, but grab the router scenario of the second... rendering the view on navigation, but exposing an event in case I want to trigger that elsewhere.

Thoughts?


Solution

  • So all backbone questions usually end up with many plausible answers. In this case, I believe your second example is a more canonical/typical backbone pattern. Putting aside the tricky issue of handling loading spinners and updating after data loads, the simplified basic pattern in your router would be:

    routes: {
        'orders/view/:orderId' : 'viewOrder'
    },
    
    viewOrder: function (orderId) {
        //Use models to represent your data
        var orderModel = new Order({id: orderId});
        //models know how to fetch data for themselves given an ID
        orderModel.fetch();
        //Views should take model instances, not scalar model IDs
        var orderView = new OrderView({model: orderModel});
        orderView.render();
        //Exactly how you display the view in the DOM is up to you
        //document.body might be $('#main-container') or whatever
        $(document.body).html(orderView.el);
    }
    

    I think that's the textbook pattern. Again, the issue of who triggers the fetching of data and rerendering after it arrives is tricky. I think it's best if the view knows how to render a "loading" version of itself until the model has fetched data, and then when the model fires a change event after fetch completes, the view rerenders itself with the loaded model data. However, some people might put that logic elsewhere. This article on building the next soundcloud I think represents many very good "state of the art" backbone patterns, including how they handle unfetched models.

    In general, you can code things with callbacks or events as you prefer. However, a good rule of thumb is to ask yourself some questions:

    1. Is more than one independent logical piece of work going to respond to this event?
    2. Do I need to decouple the source of this event from the things that happen in response to it?

    If both of those are "yes", then events should be a good fit. If both are "no", than straightforward function logic is a better fit. In the case of "navigating to this URL triggers this view", generally the answer to both questions is "no", so you can just code that logic into the router's route handler method and be done with it.