View-targeted action propagating to sibling views - ember.js

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>

Related

ember element that is hidden by focus out event is blocking click event

I have an odd conundrum.
It appears that when an element is hidden by a focus-out event ember is unable to attach the corresponding click event that triggered the focus out properly. For example with the code below if the <a> tag triggers the focus-out event on the input and the code behind turns _focused to false then the selectOpts event is never triggered. It appears to only happen if the a tag is hidden as a result of the focus-out.
Also oddly it does not matter how the a tag is hidden either if i do just display:none it still also doesn't fire the selectOpt action.
Here is my code:
<div class="dropdown">
{{input value=value class='form-control' focus-in="focused" focus-out="unfocused" }}
{{#if _focused}}
<ul class='dropdown-menu'>
{{#each _filteredOptions as |opt|}}
<li><a href="#" {{action "selectOpt" opt}}>{{opt}}</a></li>
{{/each}}
</ul>
{{/if}}
</div>
Here is a ember twilldle showing the issue.
https://ember-twiddle.com/6bbdb669d19d7a498e645bb0297f1b46?openFiles=templates.components.input-autocomplete.hbs%2Ctemplates.components.input-autocomplete.hbs
In order to get it to show the issue focus in on the text area and then try to select one of the links that appear below the input. What is supposed to happen is that when you select the link it is to populate the input field with the value.
You can use just focus-in instead of both focus-in and focus-out. So when you click on input focus-in event trigger and set _focused to true. Then, in action selectOpt you set value and after that set property _focused to false.
<div class="dropdown">
{{input value=value class='form-control' focus-in='focused' }}
{{#if _focused}}
<ul class='dropdown-menu'>
{{#each options as |opt|}}
<li>
<a href="#" {{action "selectOpt" opt}}>{{opt}}</a>
</li>
{{/each}}
</ul>
{{/if}}
input-autocomplete.js
actions: {
focused() {
this.set('_focused', true);
},
selectOpt(opt) {
console.log(opt);
this.set('value', opt);
this.set('_focused', false);
}
}
I didn't include all code for input-autocomplete it's the same as before exxept actions. Also I used options array insted your filter because didn't get any results when clicked on input.

Nested each and if with Handlebars and EmberJS

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')

Select when in a loop, select single, shows multiple selected

When Ember.select is used in a {{#each}}, if I select option in one select, it shows as if it is selected in all the other selects. Below is the code and screen shots.
Code in template :
{{#each feed in model.feeddefinitions}}
{{#if isEditing}}
<td> {{view Ember.Select
content=model.sections
optionValuePath="content.id"
optionLabelPath="content.name"
prompt="Select Section"
value=selectedSection}}</td>
<td>
<button class="btn btn-primary btn-sm" {{action 'add_section_to_feed' model feed.id}}>Add</button>
</td>
{{/if}}
</tr>
{{/each}}
You are experiencing this issue because selectedSection's context is not an individual feed.
If every feed has a 'selectedSection' attribute, you can give 'value=feed.selectedSection'
Or else, you have to define an itemController for an individual feed and define the selectedSection property in it.
The problem is that all your Ember.Selects are sharing a single controller and all of them are bound to the same property in the same controller value=selectedSection.
What you need to do is have a separate controller for each Ember.Select. You need a new controller for each item, for this purpose you can use the render helper.
Example: http://emberjs.jsbin.com/xahevi/1/edit?html,js,console,output
All of your selects are bound onto the same property.
You either need to bind the value/selection onto a model property or onto a controller property for each item. You can have the each helper wrap each model in a controller as follows:
{{#each feed in model.feeddefinitions itemController='feed-definition'}}
...
{{/each}}
Basically what you have to do is -
declare item controller as {{#each itemController=DesignPhotoController}} while looping.
so that each individual object will have a separate controller.
And add
selectedSection: null,
in DesignPhotoController and access it via this.get("selectedSection") in the controller.
Here is the - FIDDLE

Accessing Values for Key in Handlebars & Ember

Is it possible to access properties in a value-for-key style in Handlebars?
I have a CollectionView which uses an ArrayController full of models. The CollectionView has a property called 'columns' that define table column configurations for rendering.
Ideally I'd be able to loop through each column (see example below) ensuring that only the columns we want rendered are rendered (and later, formatting and other attributes are applied)
<tr>
{{#each column in view.controller.columns}}
<td>
{{ view.content.[column.name] }}
</td>
{{/each}}
</tr>
This doesn't work, it just returns no content.
I've also tried these other styles to see if they'd work:
<tr>
{{#each column in view.controller.columns}}
<td>
{{ view.content.name }}
{{ view.content.[column.name] }}
{{valForKey view.content column.name }}
</td>
{{/each}}
</tr>
The valForKey helper is one I wrote (source here), which does display the correct value but doesn't bind, so the value isn't updated when the property changes.
What's the best way to handle this use case in Ember?
Thanks
Right now Ember has get helper included:
{{get object key}}
You can create a bound helper to display the value of the column
Ember.Handlebars.registerBoundHelper('dd', function(rowData, col) {
return rowData[col];
});
See the following SO answer for more details
https://stackoverflow.com/a/27477602/908842

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
}
});