Handlebars Templates Sometimes Partially Rendering - javascript

In a Handlebars.js (v1.3.0, no ember or anything) template, I have code like so (there is a lot more to the template, this is the isolated problem part):
{{#if candidate.workCities.length}}
<li><label>Work Cities:</label>
<ul>
{{#each candidate.workCities}}
{{#if this.length}}
<li>{{this}}</li>
{{/if}}
{{/each}}
</ul>
</li>
{{/if}}
And it is being bound by data that looks like this (ellipses represent unrelated data):
{
...
, candidate: {
...
, workCities: [
'New York City, NY'
, 'San Francisco, CA'
, 'Chicago, IL'
, 'Raleigh, NC'
]
...
}
}
Which occasionally (note: sometimes it works, sometimes it doesn't) results in HTML like this:
<li><label>Work Cities:</label>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</li>
The rest of the template renders fine, it's just this loop that does not and it is really, really annoying.
If anyone has any idea why this is happening (only sometimes!), your help would be much appreciated. Thanks.

Related

Handlebars render only some elements

I have the following handlebars template:
<script type="text/x-handlebars" data-template-name="index">
{{log model}}
<button {{action 'getSuggestion'}}>Get suggestion</button>
{{log suggestion}}
{{#if suggestion}}
<p>There is a suggestion</p>
{{else}}
<p>NO suggestion</p>
{{/if}}
<ul>
{{#each item in model}}
<li>{{item}}</li>
{{/each}}
</ul>
</script>
Currently, the two log work as expected, but the button between them is not rendered.
A while ago I've added another <p>text</p> right in the beginning of the template and again, it didn't render.
Do you have any idea why? And is there a specific way to debug Ember applications? I find Handlebars extremely unpredictive, with elements being rendered or not after no specific reason, and with no errors shown...
The thing was pretty simple: I was using a somewhat older version of Ember.js. Updating to the latest one made everything work again.

Sending different data to an embedded component in Ember

I've got a drag and drop setup in two views, currently. I am trying to pull those out and make reusable components out of them. At this point I'm not even worried about the actions and bringing that information back (that will be the next issue that I will look into). Right now I'm only worried about getting the proper data to display.
The templates for my current setup are:
The outside list view:
<ul class="sortable-list">
{{#each view.permission}}
{{ view App.GroupsPermissionView }}
{{/each}}
</ul>
The individual item view:
<li class="sortable-item">{{ this.displayName }}</li>
I have changed this into the following component templates:
drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{ drag-and-drop-item dadi=this.displayName }}
{{/each}}
</ul>
and drag-and-drop-item.handlebars:
<li class="sortable-item">{{ dadi }}</li>
I call this with {{ drag-and-drop dad=unselectedPermissions }} or {{ drag-and-drop dad=selectedPermissions }}
and this works fine.
Here is my issue. My other use of drag and drop does not use the field name of "displayName". The field is just "name". I'm sure other co-workers will need to also use other field names as well.
I've tried many different things to attempt to get it passed through to the inner component, but nothing has worked. I think it is a limitation in handlebars and that this will be impossible to do.
Any idea of what could be done here, if anything?
Edit: An update
I've got things somewhat closer...but now I've run into another related issue. Here's my current drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{ drag-and-drop-item self=this dadi=../field }}
{{/each}}
</ul>
Here's drag-and-drop-item.handlebars:
<li class="sortable-item">{{ dragAndDrop self dadi }}</li>
And here's drag_and_drop_helpers.js:
Ember.Handlebars.helper("dragAndDrop", function(context,value) {
return this.self.get(value);
});
I realize that context isn't being used above, I've got it in there because of testing I was doing.
Here's the thing...with the code above, I get the correct 'this'. If I return "this.self.get('displayName');" in the helper, it works. However, the ../field isn't being returned in the template. I so wish you could have nested {{}}'s...then this would work!
To get the ../field working, I found I could make the following change to drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{#if ../field}}
{{ drag-and-drop-item self=this dadi=../field }}
{{/if}}
{{/each}}
</ul>
But if I do this, 'this' isn't the right one, so I'm getting 'displayName' through, but the wrong context.
It seems I can have one, or the other, but not both.
I could really use some help here.
I got it figured out, after quite a few days of searching and trying lots of things.
I did not realize that you could use "view." to pull the information.
Here's the call to this:
{{ drag-and-drop dad=unselectedPermissions field="displayName" }}
Here's the working drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{ drag-and-drop-item self=this dadi=view.field }}
{{/each}}
</ul>
Here's the working drag-and-drop-item.handlebars:
<li class="sortable-item">{{ dragAndDrop dadi }}</li>
Here's the working drag_and_drop_helpers.js:
Ember.Handlebars.helper("dragAndDrop", function(value) {
return this.self.get(value);
});
I'm hoping this helps someone in the future so they don't repeat mistakes I've made.
Now, on to figuring out the coding for the component.js...

Assemble - page titles in Pages collection

On the Pages bit of the assemble.io docs, under Using YFM with the page variable, it has this:
<ul>
{{#each pages}}
<li>{{../page.title}}</li>
{{/each}}
</ul>
suggesting this will output the title (from each page's YFM) - if I paste that code into the top of example.hbs from the examples project it just outputs this (and I see the same thing in my own project):
<ul>
<li>Examples</li>
<li>Examples</li>
<li>Examples</li>
<li>Examples</li>
<li>Examples</li>
</ul>
It looks like the documentation has been updated since you posted this question. The correct handlebars code should be...
<ul>
{{#each pages}}
<li>{{title}}</li>
{{/each}}
</ul>
This is saying that for each page in the pages collection, write out an anchor tag that uses the title property on the current page within the loop.
I hope this helps.
The data for each page is exposed via the data object. Updated code below.
<ul>
{{#each pages}}
<li>{{ data.title }}</li>
{{/each}}
</ul>

Render Multiple View/Controller Pairs

I am currently rendering a list of views:
<ul>
{{#each newsItem in controller}}
{{view App.NewsItemView contentBinding="newsItem" class="news-item" }}
{{/each}}
</ul>
But I would like to inject a NewsItemController into each view.
I've tried using render, but this only seems to support a single view, giving the exception:
Uncaught Error: Handlebars error: Could not find property 'control'
on object .
I've found a brief mention of using control instead, but this no longer seems to be included.
So how can I render multiple versions of the same view, injecting a separate controller into each one?
{{render}} should be fixed in current master (if you build it from Github). You should be able to use it multiple times if you pass a model:
<ul>
{{#each controller}}
{{render "newsItem" this}}
{{/each}}
</ul>
{{control}} is still there but hidden behind a flag (because it's still experimental). To use it you need to do : ENV.EXPERIMENTAL_CONTROL_HELPER = true before including the ember.js file. If you can avoid using it, it would be better.
However I think the simplest approach would be to use itemController:
<ul>
{{#each controller itemController="newsItem"}}
{{view App.NewsItemView class="news-item" }}
{{/each}}
</ul>
I think you can combine them to make it simpler (I haven't tried it yet):
<ul>
{{each controller itemController="newsItem" itemViewClass="App.NewsItemView"}}
</ul>

Each iterator not outputting value of content array

I've got an arrayController that contains a list of recent search terms. When I push an item to the array it correctly displays the quantity of items on the view except for one problem...I can't get the name to print.
Here's the pertinent code
App.recentUsersArray = Em.ArrayController.create({
content: [],
addUser: function(name) {
this.pushObject(name);
}
});
<ol>
{{#each App.recentUsersArray}}
<li>
{{#view App.RecentNameView}} {{name}} {{/view}}
{{#view App.RecentNameDeleteView}}X{{/view}}
</li>
{{/each}}
</ol>
Inside this line: {{#view App.RecentNameView}} {{/view}} I've tried {{name}}. {{content.name}} but neither work. What am I doing wrong?
Try using "this": http://jsfiddle.net/s7DbE/
Or this, which is answers the question a little better: http://jsfiddle.net/s7DbE/1/
Or this fiddle, which reverses the inputs: http://jsfiddle.net/s7DbE/2/

Categories

Resources