Question

I have a sequence of page states that essentially mimic a shopping cart checkout process like so:

var ItemsCollection = Backbone.Collection.extend({
    model: ItemModel,    
    url "/items" 
});

var ItemsView = Backbone.View.extend({
    // Select item on click event here
});

var ItemsApp = Backbone.View.extend({
    // Fetch collection of items and render each ItemsView

});

When an Item is selected, I wanted to essentially change state to render Sellers of that item. The architecture would look like this:

var SellersCollection = Backbone.Collection.extend({
    model: SellersModel,    
    url "/sellers" // The item ID is stored in a session NOT in the url (So permalinks work) 
});

var SellersView = Backbone.View.extend({
    // Select item on click event here
});

var SellersApp = Backbone.View.extend({
    // Fetch collection of sellers and render each SellersView

});

So given these two states, where is the based place to instantiate a Sellers Collections, Fetch the Sellers and render the view?

I was thinking of essentially combining the SellersApp view and ItemsApp view into one serving as sort of a controller that determines which subview to render and which collection to fetch. If I do it that way, should I instantiate BOTH collections in the main app namespace and fetch the collections when needed or should I instantiate each collection only when the corresponding state (url) is called. I think the latter approach violates the Law of Demeter.

How I think I should do it.

// 1. Instantiate outside the view
var MainApp  = Backbone.View.extend({

     attributes: {
         "page": "items"
     },

     items: function(){
        // Fetch items collection and render view (listenTo used in initialize)
     },

     sellers: function() {
          // Fetch sellers
     }

});

Items = new ItemsCollection;
Sellers = new SellersCollection;

Is this a good approach? If it is a good approach, where should I tell the MainApp to change states - i.e. should I explicitly invoke the main app's fetch collection method (i.e.
in the ItemsView 'click' event, explicitly declare ItemsApp.sellers) or should I use a listener on the main app view that automatically listens for an item to be selected.

I'm essentially looking for the alternative to use router.navigate - trigger and using the router to instantiate each view/collection as I've heard this is not good practice.

Was it helpful?

Solution

Unfortunately with Backbone (especially Backbone Views) there's not really a "proper" way to do things. There's no reference convention. A lot of people who use Backbone only use the Models/Collections and don't use the Views at all.

In my opinion I would scrap having a view for a collection unless it's actually doing something important. Use the hierarchy App > ModelCollection+ModelViewCollection.

So in your case:

ItemsApp (Backbone.View)
--ItemCollection (Backbone.Collection)
  --Item (Backbone.Model)
    -- SellerCollection (Backbone.Collection)
--ItemViewCollection (Array)
  --ItemView (Backbone.View)
    -- SellerViewCollection (Array)

So your ItemsApp would create and destroy ItemViews as the ItemCollection changes (listen to the events).

The ItemView is responsible to know when the user selects it based on an event. It can then choose to populate the SellerCollection on its model when it is selected. When unselected it could clear that collection. It also listens to changes in the SellerCollection and adds and removes views for each seller.

I don't think there's any built-in method to store a list of Backbone.Views, you probably just want to create your own array. It's up to you to keep track of the views, since a model itself shouldn't have a reference to its view.

It's worth having a global event object to act as a sort of messaging system. Backbone.View implements Backbone.Events so you can declare your app object globally and then listen to any events. You should only use that when you need to though, otherwise you should just listen to events directly instead of triggering them globally. For example, your ItemView may have a "Back" button which raises an event on itself called "back", while your AppView is listening to the events on the the active ItemView and when it wants to go back the AppView will make the necessary changes to the DOM and de-select that item.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top