Handlebars: How to reuse template after dynamically updating array of objects - javascript

Okay so here is the the template I'm using
<script id='goalNavTemplate' type="text/x-handlebars-template">
{{#each this}}
<div class="bubble" data-dismiss="modal" data-Name="{{name}}"
style="background:{{color}} url(images/{{icon}}IconSmall.png)
no-repeat 13px 14px;"></div>
{{/each}}
</script>
And then I'm adding my objects in the array to the DOM with handlebars.
var template = Handlebars.compile($('#goalNavTemplate').html());
$('#selectGoalModal .modal-body').append(template(goals));
This works how I like, yet what I would like to do next is be able to update the DOM when a new object is added to the array (through user input). Yet if I call:
$('#selectGoalModal .modal-body').append(template(goals));
again it will add all the objects to the DOM and not just the last one. My current workaround is to remove the previously added elements and then use the above line of code after the array is updated. I was wondering if there is a more efficient way of doing this using handlebars? Like is there some way to bypass #each and just append the last object in the array? Would you use a helper? If so, how? Any insight into this would be awesome.

You can add some flags to goals item, e.g. datatime and check it by HB:
{{#each this.items}}
{{#ifCond this.dt '>=' ../options.dt }}
<div class="bubble" id="bub-{{id}}" style="background-color:{{color}};">
{{id}} - {{name}}
</div>
{{/ifCond}}
{{#updateDOM "#bub-" id dt}}{{/updateDOM}}
{{/each}}
http://jsfiddle.net/2jvndb0L/5/

Related

How to check if {{#index}} is even or odd in Handlebars?

I'm iterating through an array, but I want to change the div color according to whether the index is odd or even.
Handlebars is not recognizing {{#index}} within an if statement, such as this:
{{#each org as |building i|}}
{{#if (isEven {{#index}})}}
...
{{/if}}
{{/each}}
the isEven is a helper I created to check. It works well, but I can't seem to pass the index to it.
Please keep in mind that I'm using Express Handlebars.
Try it without the brackets around #index
{{#if (isEven #index)}}
...
{{/if}}

meteor.js & spacebars - passing variables in nested loop

Context
I’m trying to use Handlebars to loop through events and then nested loop through images. I need to select only the images that correspond to the event that the event loop is currently on.
Problem
I can’t pass the _id of the event inside the image nested. Is there a work-around for this? I realize I can pass variables through a helper but it would be good to know if there is a simpler way.
The following is meta-code for what is not working so far:
//attach venue image to each venue
{{#each myVenues}}
{{#each myImages}}
{{#if myVenues._id == myImages._id}}
<img src="{{this.url}}>
{{/if}}
{{/each}}
{{/each}}
Any help would be appreciated!
More recent versions of spacebars supports referencing the parent. Try:
{{#each myVenues}}
{{#each myImages}}
{{#if ../_id == myImages._id}}
<img src="{{this.url}}>
{{/if}}
{{/each}}
{{/each}}
EDIT:
Christian Fritz pointed out that your conditional logic in the if statement won't work with spacebars. If you set up a helper to evaluate the conditional logic, you can still get this working:
{{#each myVenues}}
{{#each myImages}}
{{ifequals ../_id myImages._id}}
<img src="{{this.url}}>
{{/if}}
{{/each}}
{{/each}}
Then in a helper:
Template.registerHelper('ifequals', function(a,b) {
return a === b;
});

Handlebars expression outside of #each helper

How can I add a dynamic class name in an #each block to my Handlebars template, where the class name isn't part of the block scope?
<div class="{{className}}>...</div>
{{#each items}}
<div class="{{className}}">
...
</div>
{{/each}}
The first <div> will see the class name, whereas the second one in the #each block doesn't, because it is now looking for a className in items.
Is it possible to see outside of the items scope in the #each block?
You need to go back one scope (or possibly more), using ../ to access a global variable. In your case if your pass i className as one attribute and ìtems`as another, your code should look like this:
{{#each items}}
<div class="{{../className}}">
...
</div>
{{/each}}
#root.classname will help on any depth of scope.

Emberjs - Accessing a parent inside {{#each}} loop

I've searched and searched and I cannot find the solution to the following question:
How do you access a parent inside an each loop?
So here's the scenario, I need to pass an id of the parent with the action helper within a nested each loop.
{{#each}} {{! iterating the model here (arrayController) }}
{{#if showingApplicants}} {{! this is set by a button that changes a property inside this particular model object}}
{{#each applicants}}
<button {{action addLabel _id}}>Add Label...</button>
{{/each}}
{{/if}}
{{/each}}
I have tried doing ../_id and ../../_id. Both of which represent an undefined value. Any clues? ALSO: Is it possible to pass two values in the action helper?
You can create variables on your #each blocks so you can refer to them on any context
{{#each x in content}}
{{#if x.showingApplicants}}
{{#each applicant in x.applicants}}
<button {{action addLabel x.id}}>Add Label...</button>
{{this.controllerProperty}}
{{x.parentModelProperty}}
{{y.childModelProperty}}
{{/each}}
{{/if}}
{{/each}}
You could also not name applicant, but if you start by naming the outer context, I would suggest doing it for the nested each as well for consistency and to avoid possible name clashes (between the outer variable and child properties).
Hope this helps
The workaround for this issue was to map out the model data to have an id object that contained the parent id and the child id.

Meteor: Re-use template with different data

I've got a few templates which list items (log lines, users) and style them accordingly in tables. Now I've added a "search" page which searches for a string in different item types and displays them on one page. In terms of layout, I want to reuse the original templates, but obviously with the data returned by the search.
How can I do that without duplicating the template itself in the HTML file?
Put another way: How can I use the actual data from the top-level template in the sub-templates.
Small example:
<template name="user_list">
{{#each user_list}}
</template>
<template name="users">
{{> user_list}}
</template>
<template name="search">
{{> user_list}}
{{> group_list}}
</template>
In .coffee:
Template.users.user_list = ->
[a,b,c,d]
Template.search.user_list = ->
[b,c]
Maybe this is an easy one, which would show how little I really understood about Meteor.
Just put the template you want to use inside the {{#each}} statement. Then each item in the array will be the context for that inner template.
HTML file
<template name="users">
<ul>
{{#each UserArr}}
{{> userItem}}
{{/each}}
</ul>
</template>
<template name="userItem">
<li>{{username}} {{profile.name}}</li>
</template>
JS file
Template.users.UserArr = function()
{
return Meteor.users.find({});
};
another solution is to put your request in a Session attribute and check for its existence when querying for the users. By default Session.get("userQuery") would return undefined but once you enter something in the search field you change that with Session.set("userQuery", {type: "something"})
Now in the coffeescript you could say:
Template.users.user_list = ->
if(Session.get("userQuery"))
[a,b,c,d]
else
[b,c]
or alternatively use a MiniMongo query because it is much nicer :-)
the nice thing is that your HTML will rerender because it is reactive to the Session's content.

Categories