Nested each and if with Handlebars and EmberJS - ember.js

I have two list of models which have relations.
A has many B
I loop through B with {{#each}} and generate a <table> with it and every row has a <select> where all As, that exist, are listed.
If an B belongs to an A it should be selected in the <select>
Example:
<table>
{{#each b in listofb}}
<tr><td>
<select>
{{#each a in listofa}}
{{#if b belongsto a}}
<option selected>a.someAttribute</option>
{{else}}
<option>a.someAttribute</option>
{{/if}}
{{/each}}
</select>
</td></tr>
{{/each}}
</table>
There is probably a way to do this with handlebar-helpers, but I don't know if I can use their output later with Ember controller actions.

Use Ember.Select http://emberjs.com/api/classes/Ember.Select.html
{{view 'select' value=someControllerProperty}}
It helps you keep logic inside the controller.
Now, in the controller you can react upon changes to the value selected with:
processValueChange: function() {
// do stuff
}.property('someControllerProperty')

Related

Ember passing multiple list items in template

Is it possible to pass multiple list of items in template using {{each}}
Can someone guide me on what I am doing,
in my sales-orders.hbs below is my currenet code.
{{#each model as |detail|}}
<li>{{sales-orders-grid detail=detail}}</li>
{{else}}
Blank
{{/each}}
</ul>
Then calling the sales-orders-grid component
Shipping Method
<div class="col-xs-12 col-md-12 col-sm-12 products-item-products border-left padding10">
<ul>
{{#each shippingMethod as |sm|}}
{{sales-orders-grid-shipping-method sm=sm}}
{{/each}}
</ul>
</div>
In my sales-orders-grid-shipping-method component calling is this:
sm.shippingMethodName
What I'm trying to achieve here is to pass list of items in {{each}} in my main template. Is it possible?
To change scope you can use the "with" helper.
http://emberjs.com/api/classes/Ember.Templates.helpers.html#method_with
{{#with user.posts as |blogPosts|}}
<div class="notice">
There are {{blogPosts.length}} blog posts written by {{user.name}}.
</div>
{{#each blogPosts as |post|}}
<li>{{post.title}}</li>
{{/each}}
{{/with}}
I think you can nest multiple "with" helper.
I think the way to go is to restructure your data as:model.list1,model.list2,etc.
Then pass the model and use as necessary.And use nested each to acheive the grid.
Iam only posting this as an answer because I can't comment yet.
So, do get back to me for Clarifications.

Get property by variable name

I want to render a table using emberjs templates. The table should resolve the columns to be rendered dynamically:
<table>
{{#each item in this.items}}
<tr>
{{#each colName in this.columnNames}}
<td>{{item.[colName]}}</td>
{{/each}}
</tr>
{{/each}}
</table>
However, I think handlebars tries to access the property colName of an item. How can I access the property dynamically?
UPDATE: As Visualize pointed out in the comments, there is now a native get helper. You should prefer that over the implementation below (which may not update properly with newer versions of Ember.)
I'm not sure if Handlebars is able to dynamically resolve a variable like that (at least out of the box). I would probably write my own helper.
Ember.Handlebars.helper('getProperty', function(object, property, options) {
return Ember.get(object, property);
});
Then in your template:
{{#each item in items}}
<tr>
{{#each colName in columnNames}}
<td>{{getProperty item colName}}</td>
{{/each}}
</tr>
{{/each}}
And if my understanding of Ember bindings is correct, the helper should re-render any time item or colName is changed.
{{#each item in items}}
<tr>
{{#each colName in columnNames}}
<td>{{get item colName}}</td>
{{/each}}
</tr>
{{/each}}
Using get helper.
Thank you.

View-targeted action propagating to sibling views

I'm trying to implement a basic table, with two rows for each player object. One is the edit row, filled with text fields, the other is the view row.
In my main template I'm using a CollectionView to render out the set of rows (players is a collection)
<table>
{{view Ember.CollectionView contentBinding="players" itemViewClass="App.PlayerView"}}
</table>
I then defined a custom view to receive the click action:
App.PlayerView = Ember.View.extend({
templateName: 'rosters/player_view',
isShowVisible: true,
actions: {
toggleVisibility: function(){
this.toggleProperty('isShowVisible');
}
}
});
Finally, I created the template for the view:
{{#if view.isShowVisible}}
<tr>
<td>{{view.content.name}}</td>
<td><a {{action "toggleVisibility" target="view"}}>Edit</a></td>
</tr>
{{else}}
<tr>
<td>{{input type="text" value=view.content.name}}</td>
<td><a {{action "toggleVisibility" target="view"}}>Done</a></td>
{{/if}}
What I'd like to happen is that when I press the "Edit" link, it hides the text row, and shows the input row. What's happening is that it works fine if I press the first link, but, say I press the 10th link down, it will hide the show rows of 1-10, and then only show the edit of 10. It's almost like the event is propagating to the sibling views from the collection, or their attributes are somehow linked?
I tried setting "bubble=false" on the action, but that didn't solve anything, neither did returning false from my action, or preventing propagation inside there. An alert statement inside the action indicates that it's only being called once (so, not once for each sibling view). I'm new to Ember, so I'm open to any suggestions over what I'm doing wrong!
It's actually because of missing closing tr tag in the else statement. Although this is ultimately the issue, I think when metamorph rips out and adds the table rows the browser has issues, but that can easily be remedied by pulling the tr tags out of the if statement.
http://emberjs.jsbin.com/EXEnUZE/1/edit
<script type="text/x-handlebars" data-template-name="rosters/player_view">
<tr>
{{#if view.isShowVisible}}
<td>{{view.content.color}}</td>
<td><a {{action "toggleVisibility" target="view"}}>Edit</a></td>
{{else}}
<td>{{input type="text" value=view.content.color}}</td>
<td><a {{action "toggleVisibility" target="view"}}>Done</a></td>
{{/if}}
</tr>
</script>

Ember js: accessing variables within a {{view}} helper

I have the following template where I loop over a list of objects and want to have a checkbox that is bound to a field isChecked for that object. This needs to be in a view helper in order to get the for tag to work (I think). When I do this I can't seem to figure out how to keep the binding with the isChecked field.
{{#each listEntry in listEntries}}
{{#view}}
{{view Ember.Checkbox viewName="checkboxView" checkedBinding="listEntry.isChecked"}}
<label {{bindAttr for="view.checkboxView.elementId"}}>Option 1</label>
{{/view}}
{{/each}}
Your question is similar to that, but that approach not work, I think is because the each helper.
But one of the comments say about nesting your component in the label.
I have done that and works.
{{#each listEntry in listEntries}}
<label>
{{view Ember.Checkbox viewName="checkboxView" checkedBinding="listEntry.isChecked"}}
Option 1
</label>
{{/each}}
I have created a jsfiddle showing
This is what I ended up doing. The problem I kept having was the need for the binding for the "for" attribute was not working in conjunction with the checked binding. Things were out of scope. If anyone has a better way to accomplish this, please let me know.
{{#each listEntry in ListEntries}}
{{#if ../isCheckable}}
{{#with ../listEntry}}
{{#view listEntryBinding="this"}}
{{view Ember.Checkbox viewName="checkboxView" checkedBinding="listEntry.isChecked"}}
<label {{bindAttr for="checkboxView.elementId"}}></label>
{{/view}}
{{/with}}
{{/if}}
{{/each}}

How do I establish associations between multiple ember views and their associated objects?

I'm confused about the relationship between templates, views and models.
I understand that one of the primary roles of a view is to translate primitive events into semantic events, but I'm unclear how I should provide the necessary data to a view.
I've got a calendar_month template. The associated CalendarMonth object has an array of CalendarWeek objects, each of which has an array of CalendarDay objects. (These are not models, since they don't persist -- they're objects, generated in the CalendarMonthRoute).
So my template looks like this:
<table>
{{#each week in weeks}}
<tr>
{{#each day in week.days}}
<td>
{{#view App.CalendarDayView}}
{{ day.monthDay }}
{{/view}}
</td>
{{/each}}
</tr>
{{/each}}
</table>
I'd like each of the CalendarDayView to respond to clicks, but I don't know how to get access to the specific calendar day object, which should be associated with each corresponding CalendarDayView.
App.CalendarDayView = Ember.View.extend({
click: function(evt) {
// do something here... but how do I know which day was clicked?
}
});
I assume it's likely I'm not setting this up properly. Should each CalendarDay view have it's own associated instance of a CalendarDayController, providing proxy access to the corresponding CalendarDay object? If so, wouldn't that then require multiple instances of the CalendarDayController? (My understanding is that the controllers are singletons -- only one of each type should exist.)
Any advice much appreciated.
This can be easily achieved by using an action helper, with which you can easily pass context objects to handler methods:
<table>
{{#each week in weeks}}
<tr>
{{#each day in week.days}}
<td>
{{#view App.CalendarDayView}}
<a {{action yourAction day target="view"> {{ day.monthDay }} </a>
{{/view}}
</td>
{{/each}}
</tr>
{{/each}}
</table>
And the corresponding View:
Vollipop.CalendarDayView = Ember.View.extend({
yourAction : function(day){
// perform your work on the day
}
});