3

I've been running into a few situations recently, where I have multiple views on the page that need to be backed by a single model. This way, just by modifying the model, all of the relevant views will automatically update their appearance. The problem is, in order to achieve this atm, I would need to write code that actively seeks out these models. I will occasionally get lucky and have a model provided to me through an event handler, but usually this isn't the case. I'm looking for a good way to have a single instance of a model on the page at a time, and then just references to that model everywhere else. How do people commonly handle this need? Backbone-relational handles it by keeping a central store using lawnchair.js, and I have heard of people using a single global collection to keep a registry of all of the models.

JayD3e
  • 2,147
  • 3
  • 21
  • 30
  • Would it be as simple as having a parent view that handles the model and rendering of the child views, re-rendering them when the model changes? – Evan Davis Dec 20 '12 at 20:50
  • Are the views on the same page (the same route)? – Lukas Dec 20 '12 at 21:08
  • Mathletics: That wouldn't work in my case, b/c I have multiple completely separate views that need to be backed by the same model. Lukas: yah they are on the same page. – JayD3e Dec 20 '12 at 21:31

1 Answers1

4

Short Answer:

One model shared by multiple views (which you could call "duplicate models") is actually a perfectly valid (and useful) Backbone pattern; it's not a problem at all. From what I can tell the problem here is that it's difficult to get that model in to the multiple views, and therefore I'd suggest solving that instead.

Longer Answer:

The problem with passing a model to multiple views is that it inherently couples views together (in order to provide that shared model to each view, the parent view needs to also have that model, as do any "in between" views). Now as programmers we've been taught to keep things as encapsulated as possible, so coupling views might seem "wrong" at first. However, couple views is actually desirable: the key thing is to properly limit which views are coupled.

@Shauna suggested an excellent rule of thumb for this: "a view only cares about itself and creating its children." If you follow this rule, the coupling between your views won't become problematic, and you'll be able to create flexible, maintainable code (far more maintainable than if you were to use global variables, as then you'd really lose encapsulation).

In light of all that, let's examine a quick example. Let's say you have views A, B, and C that all use model X, but you're building A, B and C in totally different places in the code (making it difficult to share X between them).

1) First, I'd look at why A, B, and C are being built in such different spots, and see if I can't move them closer together.

2) If they have to be built so far apart, I'd then look at whether they have something in common I can exploit; for instance, do all those spots all share some related object? If so, then maybe we can put X on that object to share it with all our views.

2) If there's no connection either in code placement or in common variables between A, B, and C, then I'd have to ask "should I really be sharing a model between them at all?"

Boring Story About Author:

When I first started using Backbone, I would often find myself arguing with my co-workers because I wanted to make global variables, and they were firmly against them. I tried to explain to them that if I couldn't use globals I'd have to pass models from view A to view B to view C to view D to view E, when only E would actually need that model. Such a waste!

Except (as I've since learned), I was wrong. Globals are a horrible idea, at least from a maintainability standpoint. Once you start using them, you quickly have no idea what code is affecting what, because you lose the encapsulation you'd normally have between views that use that global variable. And if you're working on a meaningfully large project (ie. one that is worth using Backbone for) encapsulation is one of the only ways to keep your code sane.

Having used Backbone a lot in the time in between, I now firmly believe that the right answer is to pass your model to your view as you create it. This might mean passing models between intermediary views that don't directly use them, but doing that will give you much better, more maintainable code than if you passed models around via globals. As awkward as it may feel at first, passing the models in to the views when you create them is proper practice.

Once you get more familiar with Backbone you will likely find that you only rarely need to pass a model through more than one intermediary view. In fact, you'll likely notice that whenever you find yourself having to pass a model between more than one view that you've detected a "code smell", and that the real issue is that your code needs refactoring.

But as with everything else on Stack Overflow, your mileage may vary ;-)

machineghost
  • 33,529
  • 30
  • 159
  • 234
  • Completely agree with this. I have also learned to pass the model directly to a view upon creation. This is a design decision that I am very strict about, as it results in less confusion down the road. However, it still isn't really an answer to my question. You can still explicitly pass a model into a view after obtaining it from the global registry of models. The overarching point, is that I am trying to find a good way to avoid duplicate models(models with the same id) on a page. – JayD3e Dec 20 '12 at 21:34
  • 2
    I can't speak for every situation, but based on my experience building a fairly robust Backbone site, I don't think "duplicate" models are a problem. Well, if you truly had multiple identical models that would be a problem, but "duplicate" in the "one model shared by multiple views" sense is actually a perfectly valid (and useful) pattern, not a problem at all. From what I can tell your problem is more the fact that it's difficult to get that model in to the multiple views, and therefore I'd suggest looking at whether you can structure your views differently to make that easier. – machineghost Dec 20 '12 at 21:48
  • 1
    For instance, if you have views A, B, and C that all use model X, but you're building A, B and C in totally different places in the code (making it difficult to share X between them), I'd look at why A, B, and C are being built in such different spots. If they *have* to be, I'd then look at whether those spots all share some related object (and then maybe put X on that object). And if there's no connection either in code placement or in common variables between A, B, and C, then I'd have to ask "should I really be sharing a model between them at all?" – machineghost Dec 20 '12 at 21:50
  • Ok gotcha, that makes a lot of sense, and answers my question. The only thing I would argue about this scenario, is that it makes the views pretty coupled from what it seems like. You have to go get the model from someplace(or places) in all of the locations where you are creating another instance of A, B, C. Backbone-relational did this nicely by overriding all of the sync operations so that it is impossible for identical models(models with the same id) to get created. If you're interested in seeing my exact situation, here it is http://i.imgur.com/kAUD1.jpg. – JayD3e Dec 20 '12 at 22:10
  • 2
    @JayD3e - The coupling depends largely on your overall architecture. I don't know about machineghost, but when I last did a backbone app, I followed the rule of "a view only cares about itself and creating its children." Part of "creating its children" involves passing it a model or collection to use. The child views are dependent on the parent view, anyway, just as an `
  • ` is dependent on the existence of a `
      ` or `
      `, so there's not really much, if any, additional coupling when passing a parameter in.
  • – Shauna Dec 20 '12 at 22:17
  • @machineghost maybe change your answer to more along the lines of what you mentioned earlier? And I'll mark it as best answer. – JayD3e Dec 20 '12 at 23:11
  • I've edited it ... the final version came out a little long, but hopefully it will be useful to future readers. – machineghost Dec 21 '12 at 02:28