This approach seems like a reasonable way to go ... but you also seem to be doing a bit more rendering than you really need to. If I understand the premise correctly, you have a situation like this:
... and the data for the MainView is changing, while the data for the SubViews is not.
So ideally, just re-render the top part of the MainView, and leave the SubViews alone. Instead of trying to reuse the same "render" function, imagine doing this instead:
... where the hypothetical "renderMainContent" function just renders the template for the top half of the box. Or, maybe the top half of the box is a sub-view in its own right that can listen to its own events. Or, maybe you don't even need a template, and you can just update a couple of granular fields and/or attributes with jQuery. Whatever works.
Yep, I was wondering why "render" would need to be called multiple times.
I usually start off by doing that because I'm lazy, then something usually bites me in the ass (usually - oh hey, we need a transition effect).
And the end result is a bunch of "sub rendering" methods that get called in render ... and as callbacks from model change events. (It's awfully nice when you have to load everything off the server - no default state in the DOM.)
I completely agree with the small render helpers, we've been using that too and it works amazingly. I'll probably write about that next. But I still want `render` to be able to be called multiple times without breaking because it's a public method.
I'd love to read an article about how you guys handle transitions though. We've implemented a few of them, but I have yet to work on them enough to have found really nice patterns.
Absolutely. I'm not saying you should have a single gigantic render method that gets called for every single change. We use a very similar pattern to what @tristan_juricek mentions with small render helpers that get bound as change callbacks. (I'll probably write about that one next.) But since I was talking about subviews I didn't want to go into the non-subview render bits which would be where you'd want render helpers.
Regardless, I'd still have the single `render` as a parent method that renders the initial template via `$.html()` so that my render helpers aren't appending their bits into the DOM. And that parent method still shouldn't break everything if it's called twice.
And then if you wanted to be safe, you could have the render helpers check to see if the view is `rendered` before attempting to do their bit. (And `return this.render();` instead if it isn't yet rendered.)
I think you just want to factor out the part that's changing into it's own subview, and then call that subview's render function instead of rerendering mainview, or writing a one off function.
I'm not sure why there's so much significance attached to `render()` considering that it's a no-op in Backbone, and you've got an entire class to work with.
Trying to figure out how to cram everything into one function while still getting desired behaviour doesn't seem like the best way to go.
That being said, there are probably better ways to do it that don't involve Backbone, too.
Backbone.Marionette is a nice set of view classes (and a few other things) solving a lot of the typical use cases for Backbone in medium to large application. Amongst other things it provides a Layout view with a simple region manager to take care of 'full page' or large views with sub views.
Does more rendering than necessary and is still not perfect, as it won't preserve DOM state on model state changes. For example, consider <details> state (rolled up or not) - setElement won't keep it.
IHMO, somehow better (but more verbose) approach is to consider view as a FSM. Each state may render view's complete representation (using the template), while each transform (an edge of view's Moore machine) may transform DOM tree as necessary (i.e. just update necessary elements instead of re-rendering a whole subtree, if possible).
I belive, this could be automated (as DOM is, essentially, a tree, differences between states could be found algorithmically), but haven't really tried it that way.
I took the approach of making a class called a "ModelView" which adds a few things - one of which is an "On Render" event that fires after the view renders. we do all of our jquery binding in our onrender function and so whenever the view re-draws, onrender is fired and all of the jquery stuff will be re-bound.
It would be nice to have the view re-drawn more intelligently so things don't need to be re-drawn and re-bound each time. But, I couldn't think of a generic way to do that without knowing the details of the view.
backbone has very little magic in it - and the particular confusing aspect mentioned in this post has to do with ubinding events by calling .html, which has nothing to do with backbone, that's all jquery.
So ideally, just re-render the top part of the MainView, and leave the SubViews alone. Instead of trying to reuse the same "render" function, imagine doing this instead:
... where the hypothetical "renderMainContent" function just renders the template for the top half of the box. Or, maybe the top half of the box is a sub-view in its own right that can listen to its own events. Or, maybe you don't even need a template, and you can just update a couple of granular fields and/or attributes with jQuery. Whatever works.