Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbonejs, Event Aggregation and Instantiating Views [closed]

tl;dr

To what extent is the Event Aggregator pattern duplicating what Backbone.Router already does? Wouldn't it be better if Views didn't communicate with each other, even with events?

The trouble

I'm having a conceptual problem with the use of an Event Aggregrator in a Backbone application. My very basic implementation is derived from Derick Bailey's post about it.. I'm using it in Requirejs and I just define a module that extends Backbone.Events and require it in the modules where I need it.

A bit of background: The problem I was trying to solve in the first place was how best to handle transitions between views in my app. Especially automated transitions. It was clear from my reading that two obvious methods were discouraged:

  • Manually firing a navigation callback on the router with something likerouter.navigate("login", { trigger: true })

  • Manipulating the browser window.location.replace("/#login") and thus triggering the relevant routing callback.

As far as I can tell, the main objection to both these methods is a loss of the proper separation of concerns. As I can certainly see the value in avoiding Views having to know too much about each other, I looked about for a better way and found the Event Aggregator.

The problem I'm facing with the Event Aggregator, though, is made quite obvious from Derick Bailey's example on his blog post. The views that respond to the events are already instantiated. Any view that is not already instantiated will naturally not respond to any events. So if, for example, I want an event to instantiate a new View as a result of some logic, I either:

  • Instantiate a new instance inside the current View. In this case I lose most of the advantage of the approach, because now my Views need to know about each other again.

OR

  • Create some kind of central event-handler that instantiates new Views based on specific events. Which sounds a lot like the original Backbone Router to me. It seems like I could just separate the logic for each Router callback into various Controllers and I'd have the same clarity.

My second problem is perhaps more general. I feel like the Event Aggregator encourages active inter-communication between Views: admittedly in a decoupled way. Ideally though I'd like to keep that to a minimum. Really I want my user to perform fairly self-contained actions within a defined area and then transition to a new area. Am I being naive, in hoping to sustain that?

I feel like I must be missing something obvious, but right now it feels like the Event Aggregator solves the problem of inter-View communication (which I'm not sure I want), but ends up replicating the Router with regard to View management. The problem I have with that is that I'll have two Event systems acting in parallel.

What I'm really looking for is a sensible, reasonably lightweight pattern for handling the instantiation of Views using the Event Aggregator. I know I could look into Marionette, but I'd prefer to understand this on my own terms first, before diving into another Framework.

like image 388
Daniel C Avatar asked Jan 28 '26 14:01

Daniel C


1 Answers

Oh backbone, confusing as ever. Everyone still has differing opinions on how a good application should work.

So here's my opinion.

For your first problem, have you considered just using an anchor tag in one of your templates?

<a href="/#login">Login</a>

For your second problem, I'd take a page from other frameworks. Before our company switched away from backbone/marionette we tried to adopt the flux (redux) architecture on top of backbone. It has worked out pretty well for some applications that stayed on backbone.

Adopting that architecture just meant defining some best practices. I think the following rules could work for you:

  1. The event aggregator will be the only thing that can fire route changes directly.
  2. At minimum 2 levels of views (or objects) are needed for any page.
  3. The top most views is called a "smart" or "highly coupled" view (or object). It will allow you to hook into the event aggregator and then pass data or callbacks downward. They can represent layouts or can be mostly devoid of style and just transform event aggregator callbacks to something the generic views can work with.
  4. The 2nd level and below should be designed in a decoupled way. We can call them "generic" views, and they can accept handlers as arguments. This is how they communicates with the outside world.
  5. This means, views have APIs and smart views need to adhere to those APIs.

Quick Example:

function init() {
    // this level is highly coupled, and knows about the events
    // that will occur
    var aggregator = new Backbone.Events();
    aggregator.on('gotoLogin', function() {
        router.navigate("login", { trigger: true });
    })

    function gotoLogin() {
        aggregator.trigger('gotoLogin');
    }

    // the Todo class is generic, and defines an API that expects
    // a gotoLogin callback
    new Todo({
        el: '.js-todo',
        gotoLogin: gotoLogin,
    });
    // the Header class is generic, and it also expects 
    // some way to navigate to the login screen.
    new Header({
        el: '.js-header',
        gotoLogin: gotoLogin,
    });
}

If you are building your application as some sort of single page app. This will cause you to nest views, which isn't the end of the world, but it does become tricky with backbone, but is still doable. In fact, you may be able to automate creation of child views (see marionette). I bring this up because it seems vaguely related to the original question around de-coupling. I think the nested view problem in backbone is particularly problematic.

I believe people over-emphasize reusable code and decoupling. Honestly, there needs to be some amount of coupling. Finding an acceptable level is difficult. Defining it when everyone using backbone has differing thoughts on it, is very difficult. My recommendation is that you and your team should figure out a system that works well for you in backbone land and stick to it otherwise chaos will surely ensue.

like image 200
Parris Avatar answered Jan 30 '26 04:01

Parris