How to design a controller in Backbone.js?

你说的曾经没有我的故事 提交于 2019-12-11 02:22:29

问题


I am interested in having a controller to coordinate rendering, event processing, URL router navigation and network access. A bit similar to what a Controller does in Spine: http://spinejs.com/docs/controllers

In the realm of Backbone, what I could find so far is an article by Derick Bailey: http://lostechies.com/derickbailey/2011/08/28/dont-execute-a-backbone-js-route-handler-from-your-code/

In Derick's code however, the Controller seems not to be used anymore within the Routes. Also, I was wondering, if anyone has a clearer code example, that shows the benefits of having a Controller coordinating Backbone components?

PS I am aware of the Controller in Marionette, but it would be great to see a Backbone code example without the Marionette dependency.


回答1:


First of all, I use Marionette.js, but for the controller, I use a plain object.

I divide the code for apps. So, if in my case, I have a Note taking app, I have:

  • an app for taking notes
  • an app to edit the categories
  • an app for authentication, etc.

Within an app, i.e notes, I divide it in a RESTful way. List, Show, etc.

Taking list for example, what I have is a controller to manage this part of the app. How?

Something along the lines (you will see Marionette code, but I guess you can do it in a Backbone way, but otoh, I would really recommend Marionette):

List.Controller =  
  listNotes: ->
    notes = App.request "notes:entities"

    App.execute "when:fetched", notes, =>

      @layout = @getLayoutView()

      @layout.on "show", =>
        @showNotes notes
        @showForm notes

      App.mainRegion.show @layout

  showNotes: (notes) ->
    notesView = @getNotesView notes
    notesView.on "childview:edit:note", (iv, note) =>
      App.vent.trigger "edit:note", notes, note, @layout.formRegion
    @layout.listRegion.show notesView

  showForm: (notes) ->
    App.execute "new:note:view", @layout.formRegion, notes

  getLayoutView: ->
    new List.Layout

  getNotesView: (notes) ->
    new List.Notes
      collection: notes

The controller is a plain javascript object. What it does is ask for a collection of notes (if not using marionette, you can retrieve the notes collection like you want). Then we wait until the notes has been fetched (using promises).

When we have the notes, we create a layout (you can use what you want and if you like layout idea you have layoutManager), when the layout has been shown, we show the notes list and the form (to enter new notes).

Then we add the layout to the desired region (again, layoutManager would work for non marionette user).

To show notes, we retrieve our view and we show it in the region desired to show the notes (ignore the other code).

Now the interesting part of using a controller AKA coordinating all the stuff.

We don't want the views doing any kind of business work, like add notes, remove notes... So when we click on a edit note (in the list notes view) what we do is just trigger an event (You can create your own event aggregator with one line of backbone code) and then the controller will listen for it and it will do what you need to do to edit notes. In my case, I bubble up the event to a file which manages all this RESTful controllers and then call the Edit Controller in other part of my app.

Is the same thing I do for the new note, I bubble it to another part of my app.

So, controllers, I use controllers to show the views I need for this part of the app, To do what the views needs to do which doesn't belongs to a view, like CRUD operations or transitions to other routes.

You asked about router. The good part of Marionette router (sorry, here I will talk about marionette) is that we can use a plain object to feed the router. What are the advantages here?

Imagine this:

class NotesApp.Router extends Marionette.AppRouter    
    appRoutes:
      "": "listNotes"

API =
  listNotes: ->
    NotesApp.List.Controller.listNotes()
  newNote: (region, notes) ->
    NotesApp.New.Controller.newNote region, notes, NotesApp.categories
  editNote: (region, notes, note) ->
    NotesApp.Edit.Controller.editNote region, notes, note, NotesApp.categories

App.commands.setHandler "new:note:view", (region, notes) ->
  API.newNote region, notes

App.vent.on "edit:note", (notes, note, region) ->
  API.editNote region, notes, note

App.addInitializer ->
    new NotesApp.Router
      controller: API

(I deleted some code, so don't try to struggle where some params come from).

This is a router in Marionette which is initialized using that API object. The advantage is that I can access that API object from the router and from the other code.

So when I hit that route, I go to the listNotes function and well, you saw what I do there. Remember how I bubbled up the edit and new views? They stop here, here I listen for those events and I just call the proper function in the API object. The good part is I decide to create another route to go to the new form, I just need to add the route. The code is there, no need to change any code.

Well, this ended to be a giant response, but I wasn't able to explain the responsibilities I give to a controller without this :P

As final words, I highly recommend using Marionette because only provides good stuff to backbone with absolutely no drawback.



来源:https://stackoverflow.com/questions/16769087/how-to-design-a-controller-in-backbone-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!