I have a view, which holds handlebars template. that template consist of another partial template. that partial template holds a list of results, which i am using in different parts of my app. anyhow, when trying to filter the results, i'd like to render only that part. meaning the backbone view should not render the whole view just the partial. can it be done?
1 Answers
Yes, it's possible. The easiest way is to execute the whole template as you do when rendering the complete view, but only replace the the part you need in the view's el
.
Something like:
template: Handlebars.compile(templateHtml),
render: function() {
//let's say your render looks something like this
this.$el.html(this.template(this.model.toJSON());
},
renderList: function() {
var html = this.template(this.model.toJSON());
var selector = "#list";
//replace only the contents of the #list element
this.$el.find(selector).replaceWith($(selector, html));
}
Depending on how dynamic your template is, you may have to call this.delegateEvents()
after replacing the list for the view's events to work correctly.
Edit based on comments:
To clarify, the method I propose here does execute the view's main handlebars template again, but it doesn't render the whole view again.
Step by step:
Execute the Handlebars template function as you do in normal render.
var html = this.template(this.model.toJSON());
The variable
html
now contains a string of HTML markup. Nothing has yet been rendered.Define a selector for the element, which you would like to re-render.
var selector = "#list";
Find the DOM element to replace. This presumes that you have already rendered the view once. Otherwise there will be no
#list
element withinthis.$el
.this.$el.find(selector)
Find the corresponding element in the templated html string, and replace the existing element with the new one:
.replaceWith($(selector, html));
This will only replace the #list
element that's currently on the page. Anything outside #list
will not be re-rendered or touched in any way.
The main reason I propose you do it this way instead of executing and rendering the partial template separately is that your view doesn't need to know anything about the implementation details of the template and the templating engine. All it needs to know that there is an element #list
. I believe this is a cleaner solution, and keeps your template details separate from your view logic.

- 35,324
- 3
- 105
- 112
-
still can't get it to work...my template inside the view is not constant, the initialize method defines it. so i was trying to set it up again before....my method looks like this: this.template = Handlebars.compile($('#tmpl-news-partial').html()); var html = this.template({news: this.collection.toJSON()}); var selector = "#newssList"; this.$el.find(selector).replaceWith($(selector, html)); this.template = Handlebars.compile($('#tmpl-list-news').html()) – tomerz Jan 31 '13 at 12:21
-
@tomerz, what's up with re-compiling the template in the end? Also, is the list id actually `#newssList` with two `s`'s? Also notice that this only works after you've already rendered the template once fully. – jevakallio Jan 31 '13 at 12:31
-
lol, ok...since my view is using the template at the end, then i am setting it up before, using it, and then setting it back to the old value. the list id is not newss.... ;) – tomerz Jan 31 '13 at 12:41
-
@tomerz, you're welcome. Btw. the way you ended up solving it wasn't *quite* what I meant, but if it works, that's cool too. Also, you don't need to set the temporary template to `this.template` and then change it back, you can just call it `this.partialTemplate` or whatever, or just use a local variable. – jevakallio Jan 31 '13 at 12:49
-
i thought the template method of handlebars is using this.template, doesn't it? can i pass another template to it? – tomerz Jan 31 '13 at 12:51
-
if i am not setting it up, it is using the view's template, which is the whole template, and not the partial one – tomerz Jan 31 '13 at 12:53
-
@tomerz, oh, sorry, thought "thx" meant it worked. If you look at my answer again, you'll see that I recommend actually executing the *parent* template, and then just plucking the child node `#newsList` out of it. That way your code doesn't need to know anything about the partials etc. Just run the same code you would in normal `render`, except instead of doing `this.$el.html()` do the `this.$el.find('#newsList').replaceWith($('#newsList', html));` – jevakallio Jan 31 '13 at 12:55
-
@tomerz also Handlebars doesn't know anything about `this.template`, and it doesn't care. You can call it `var dogAndPony = Handlebars.compile(templateHtml); this.$el.html(dogAndPony(data));` and it'll work. `view.template` is just a convention. – jevakallio Jan 31 '13 at 12:57
-
no...can't render the whole view....the whole view holds a filter textbox, so i want to render only the partial – tomerz Jan 31 '13 at 12:58
-
@tomerz, I added some clarification to my answer. – jevakallio Jan 31 '13 at 14:44
-
Note that this will not work if `#list` is a top-level selector in `html`, because `$(selector, html)` is equivalent to `$(html).find(selector)`, which will only match the descendants of the set of matched items (of which `#list` will be one). So in that case you have to use `filter`. – Josh Leitzel Feb 28 '14 at 21:43
-
@jevakallio Hi, can you please look into the question posted [here](http://stackoverflow.com/questions/24115096/reloading-handlebars-partial-from-marionette-view-loses-access-to-ui-object-defi) which I have got while following your answer posted here. – Shaggy Jun 09 '14 at 06:55