Hacker News new | comments | show | ask | jobs | submit login
Rethinking Backbone.js View Rendering (elving.me)
48 points by elving 1685 days ago | hide | past | web | 30 comments | favorite

Yes, absolutely pass models directly to your views. That's what they're for, after all -- keeping together a handy bunch of methods that can display your data in ways that are terrifically useful for a view to show:



... and so on. But by all means, don't use Handlebars to do it. Use a templating engine that allows real logic, and rest easier at night. Handlebars is set up as faux-logicless templating -- A wolf in Mustache.js' clothing. Having to add Handlebars helpers just to be allowed to call a "method" (as shown in the blog post) is pretty silly example of forced indirection, no? Much more straightforward with embedded JavaScript:

    {{ model.getFullName() }}

I recently started learning EmberJS which forces the user of Handlebars. I thought maybe I was crazy, or maybe I was missing something, but your comment makes me feel a little bit more sane.

Why oh why would you ever use Handlebars over, say, Underscore's templates which allow actually logic? In my (admittedly limited) experience, both choices are equally as simple when writing simple templates, but Handlebars is a colossal pain in the ass when trying to do something significant.

The "structured" nature of Handlebars is important if you're using Ember, because it's set up specifically to allow it to parse the interpolations in your templates and determine what attributes you're binding, and so on. But if you're not using Ember, a "colossal pain in the ass" sounds about right.

Do yourself a favor and use true logic-less templates (Mustache, in all of its myriad flavors) if you really believe in that sort of thing. Or make life easy on yourself and use a programming language you already know. Embedded Ruby, embedded JavaScript, embedded PHP (the only kind there is) -- all have the virtue of allowing as much or as little code as you need and want, and allow you to do whatever you need to get the job done.

I would have the opinion that you don't mean "real logic" as much as you mean "model data". In other words if you follow the examples you give, I wouldn't see any reason that the model would not have those fields accessible directly or via a standardized "get" as opposed to direct function calls. I would argue that "real logic" in your view/template is a "real bad" idea.

Edited grammar.

I'm afraid I do mean "real logic" -- in terms of "real function calls", or "real math", or whatever else you might want to do. Let me imagine a few more examples:


    document.publicNoteCount + document.privateNoteCount

... you always can stuff all of those things into an arbitrary "viewmodel" JSON object somewhere else outside of the template, but it's frequently clearer and more convenient just to do it where it's needed -- instead of enforcing an extra layer of indirection for no real reason -- by passing around models directly.

I guess I feel somewhat strongly about this because having multiple sources for the same truth is what gets people into trouble so often with client-side apps. (Where by a "truth" I mean something like: "What are the names of the collaborators on this document".) Having that data in your model and then again in your viewmodel, and some parts of your app access it over here, and your templates access it over there, is exactly that sort of unnecessary duplication...

We agree on having a single source of truth. I'm arguing for it to be derived in a controller and not in a view.

Then the controller becomes a second source of truth, no?

Makes sense. The idea of using Handlebars instead of embedded Javascript is that the template can't actually change the model, just get data from it, so there's no real logic on the template. Of course this is all theory, as I said in the blog post, it was just an idea. Once I use this approach, I can definitely state the pros and cons.

I'm a big fan of adding a CoffeeKup template method right in the view. Then just call

    @$el.html coffeekup.render @template, @
in my render function. But I suppose that gives up keeping the html markup separate. For ui components, though, it just makes sense to me to keep the structure bundled with the functionality that way.

Yes, Handlebars is explicitly designed for logicless templating. If you need real logic in your View (which I might add is often a good time to step back and possibly refactor your solution), you can always fall back on Underscore's templating.

I frequently do this in my apps - I use Handlebars by default, but fall back on _.template() any time my view's absolutely have to have logic in them.

Since Backbone already depends on Underscore, it's harmless in terms of introduced dependencies.

You can call a method with Mustache. You don't event need Handlebars to do that.

Correct me if I'm wrong, but wouldn't the best place to combine and transform model data be in the model itself?

For trivial cases, this could be implemented in the model's 'defaults' function. (by computing the transformed field value in the function and returning a hash) If you forsee the need to update the value of the dynamic field in response to the client updating the model, you can perform the calculation again in the Model's 'validate' function.

Speaking from experience, logic in templates is convenient for trivial use cases, but can be very difficult to maintain once a project grows.

"logic in templates is convenient for trivial use cases, but can be very difficult to maintain once a project grows"

Agreed, my first thought was that there is no way to actively debug the template logic.

Exactly. We have a generic serialize() method in our models to do common toJSON. In item views, where performance is critical, the view itself transforms a subset of the models properties to JSON.

OP started using Handlebars helpers. there is no "rethinking" happening here and it hardly even pertains to Backbone.

At tout.com, we were having timing issues with view rendering, for example if the view has a flash element in it and the $el isn't in the dom yet, you can't operate on the flash element in the render function.

I summarized our new best practice here: http://tommyhallett.tumblr.com/post/37318050812/avoiding-ren...

I have a lot of canvas drawing going on in my app (charts) and ran into the same issue.

As you point out, appending the element to the DOM before everything is fully rendered can cause all sorts of re-drawing to go on. When that's a concern, I proactively set height/width dimensions on the element before adding it. In cases where that's problematic, I just have the render function of the view either update or remove the explicit height/width styling. That seems to help avoid the worst cases of redrawing/flicker.

Cool approach! I'll keep that in mind.

That was our biggest peeve with Backbone views. We fixed it by having a `renderTo` method instead of `render`. Basically, insert the $el into the DOM first, then call render.

Another benefit to this approach is it makes replacing, disposing views, creating stacked views easy ... That is when renderTo tries to insert into a container and determines a view is already in place, it can call dispose or detach on the existing view. Much simpler than Marionette regions or other view management approaches.

Isn't this a bad idea outside of formatting a number as currency?

Also, Why not let JavaScript inject your model data directly into plain vanilla HTML templates? In other words, don't use any template tags at all. These 2 projects are really piquing my interest.



Side benefit is that you can still pre/hybrid render from the server in whatever language you like.

I absolutely love Backbone, but the biggest issue for me has been dealing with complex logic in the templates. Most of the time now my render() method just builds the darn elements right in there.

as long as it is just a view and not data manipulation, what is wrong with that? You do not have to have template at all. What if your view is list generator with classes? Why having template at all?

It can get pretty messy at times.

Try https://github.com/mgutz/funcd. It's straight up CoffeeScript functions patterned after Markaby, Erector. Other CoffeeScript templates we tried did funky things with the context and closures didn't work as expected.

And when performance is a concern, you can't beat string interpolation within CoffeeScript heredoc strings.

Yep, that's usually how I start my render() method (using triple-quote strings). Then I wrap it in jquery and do dom manipulation on it.

Why can't people just use regular HTML for markup? Coffeescript is beautiful when you are composing short succinct functions but this just looks like more work for my brain.

I used coffeekup back in the day, but I just can't stand the jade-style declarative html. I also used eco for a while, but it got pretty messy too. I'm picky, I know :)

I've found it useful to abstract away render and work with before/afterRender hooks instead. I still call render which has a base implementation that calls the template, but instead of passing just the model or the model's JSON, I pass a context object that I can build up to suit my needs. This way every template is dealing with the same thing, and the whole mechanism is extensible.


I find it easier to use Handlebars first, then fall back on _.template() when you need logic in your templates. It's easy : http://brettjonesdev.com/on-templating-in-backbone/

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact