I am using Ember Version 2.5.1
I have setup checkbox, and they work when selected. But, when I select one box, for one user, all the boxes become selected for all the users. E.g if I select a team (Speedy) for Sophie, then everyones checkboxes end up checked and being on team Speedy. How do i stop this? And make it so each person can be on a different team.
e.g. the out come is a list of everyones names, (then if 'Team Speedy' is checked), next to everyones name is 'Team Speedy'.
teams.hbs;
<div class="container">
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Name</th>
<th>Team Speedy</th>
<th>Team Alpha</th>
<th>Team Invincible</th>
</tr>
</thead>
<tbody>
{{#each model as |signed-player|}}
<tr>
<td> {{signed-player.name}} </td>
<td> {{input type='checkbox' checked=speedy}} </td>
<td> {{input type='checkbox' checked=alpha}} </td>
<td> {{input type='checkbox' checked=invincible}} </td>
</tr>
{{/each}}
</tbody>
</table>
{{#each model as |signed-player|}}
<p><b>{{signed-player.name}}</b> is on the following team: <b>{{teamName}}</b></p>
{{/each}}
</div>
controllers/team.js
speedy: false,
alpha: false,
invincible: false,
teamName: function()
{
if ( this.get('speedy') ) {
return 'Team Speedy';
}
else if ( this.get('alpha') ) {
return 'Team Alpha';
}
else if ( this.get('invincible') ) {
return 'Team Invincible';
}
else {
return 'No team yet';
};
}.property('speedy', 'alpha', 'invincible'),
The main problem I see in your example, is you are not setting any properties on any of the players. You are computing only one property {{teamName}} and just displaying it once per player, which is why clicking one checkbox appears to change the team for everybody... when in reality you are not actually setting any players onto any teams at all.
The other problem i see: you need to decide if chackboxes are the right UI for your selection. can a single player be on more than one team? if so, then checkbox is fine.. if not, then a select box or a set of radio inputs are probably better.
All that being said... each player object/record needs a property that actually stores the value representing which team(s) they belong to.
You will also need an action from each checkbox/radio/select/whatever to actually set the selected value onto the player object:
Here is my example:
https://ember-twiddle.com/1fe44ad4dc0494973c494a624ead79b7?fileTreeShown=false&openFiles=templates.application.hbs%2C
there are a number of things going on here... but essentially what we are doing is using a select input of choice (for me.. radio) and using the change action from the input to set each specific player's team property... which is defined on each player object to begin with.
I use a mut helper in my action in the example.. is is a quick way to set a value in a template action.. if you wanted to use a checkbox instead.. you will most likely want to replace the mut helper and apply your own custom action in a controller.
Please follow up if you need/want any extra explianation
Related
Summary
I have a problem with a list displayed by Ember which keeps displaying extra rows each time it is visited. The extra rows are duplicates of those which were initially displayed.
Detail
In an Emberjs 2.13.0 app I have a model that looks like this :
import DS from 'ember-data';
export default DS.Model.extend({
cceIdentifierParent: DS.attr('string'),
cchCceIdParent: DS.attr('string'),
nodeType: DS.attr('number')
});
I have a route, 'diagcctreetoplevelonly', which looks like this :
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('diagcctreetoplevelonly');
}
});
And a template that looks like this :
{{diag-warningbanner}}
{{#if model.length}}
<table>
<thead>
<tr>
<th>
cceIdentifierParent
</th>
<th>
cchCceIdParent
</th>
<th>
nodeType
</th>
</tr>
</thead>
<tbody>
{{#each model as |treenode|}}
<tr>
<td>
{{treenode.cceIdentifierParent}}
</td>
<td>
{{treenode.cchCceIdParent}}
</td>
<td>
{{treenode.nodeType}}
</td>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
<p id="blankslate">
No Tree Nodes found
</p>
{{/if}}
{{outlet}}
That works fine the first time that 'diagcctreetoplevelonly' is visited - 12 rows are rendered - but on subsequent visits (without the underlying data having changed) the table rendered by the template has 12 extra rows for each time it has been visited.
Can anyone explain what i'm doing wrong ? Thank you.
EDIT: Thanks to the input from #Jeff and #Subtletree I was able to resolve this.
The problem was that the data returned had no 'id' attribute and when I created one the problem went away.
Because of the peculiar nature of the data it didn't actually matter what the id was and I didn't want to make changes to the backend so I created an id dynamically once the data had arrived on the client by creating a model level serializer and overriding the extractId method like this :
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
extractId(modelClass, resourceHash) {
var arrId = [];
arrId.push(resourceHash['attributes']['cceIdentifierParent']);
arrId.push(resourceHash['attributes']['cchCceIdParent']);
arrId.push(resourceHash['attributes']['nodeType']);
var id = arrId.join('|');
return id == null || id === '' ? null : id+'';
},
});
It wouldn't have worked in all (perhaps most ?) situations but for my case this was good enough and resolved the problem.
To provide credit where it's due I got the idea for how to do this from the answer by #Casey here https://stackoverflow.com/a/35738573/364088 .
When ember-data receives records from a server it tries to match them to records already in the store by their id. If no id's are present then it can't find a match so instead of updating them it will just add them.
You could add an id to each record or could fetch the data with ajax and not use ember-data for this model.
How can I specify a class to an item when clicked with Ember. I am using a Handlebars action on the elements of a table to sort by properties. I want to add a class to the property being sorted so I can show the user the current property being sorted. How can I do this?
I have an ember controller shown below:
App.UsersController = Ember.ArrayController.extend
title: 'Users'
count: Ember.computed.alias 'length'
sortProperties: ['username']
actions:
sort: (property) ->
console.log property
if #get('sortProperties')[0] is property
#set('sortAscending', !#get 'sortAscending')
else
#set 'sortProperties', [property]
#set('sortAscending', true)
The controller allows me to click on headings in a table to sort the table. The html is shown below:
<thead>
<tr>
<th>Action</th>
<th class="sort" {{action sort 'last'}}>Last</th>
<th class="sort" {{action sort 'first'}}>First</th>
<th class="sort" {{action sort 'username'}}>Username</th>
<th class="sort" {{action sort 'email'}}>Email</th>
</tr>
</thead>
Create a currentSort property (optional)
First, I created a currentSort property on your App.UsersController which cleans a little bit the code. We'll use it later.
App.UsersController = Ember.ArrayController.extend
sortProperties: ['username']
currentSortBinding: 'sortProperties.firstObject'
actions:
sort: (sort) ->
if sort is #get('currentSort')
#toggleProperty 'sortAscending'
else
#setProperties
currentSort: sort
sortAscending: true
Define a custom view for each <th>
You'll then have to define a custom view for the <th> which will do 2 things:
Have a class active-sort when the sort of the view is the current
Change the controllers current sort when clicking the view
It will looks like this:
App.SortView = Ember.View.extend
template: Ember.Handlebars.compile('{{view.sortName}}')
tagName: 'th'
sortName: null # (will be different for each <th> : `last`, `first`,..)
classNameBindings: [ ':sort', 'isCurrent:active-sort' ]
isCurrent: (->
#get('sortName') is #get('controller.currentSort')
).property('sortName', 'controller.currentSort')
click: ->
var newSort = #get('sortName');
#get('controller').send('sort', newSort);
Here we customized the view class names, and we handled click event on the view.
Insert a custom view for each sort
This is really simple to insert views in templates:
<thead>
<tr>
{{view App.SortView sortName="default"}}
{{view App.SortView sortName="price"}}
{{view App.SortView sortName="alphabetical"}}
</tr>
</thead>
You can test all of this in a working JSBin
I don't know if this is the best workaround, but you could have some "sort flag" that you could bind CSS on.
In your controller (in "classic" javascript) :
sortedByLast : function() { return this.get("sortProperties")[0] === "last" }.property("sortProperties.#each")
// etc ...
In your template :
<th {{bind-attr class=":sort sortedByLast:current-sort"}} {{action sort 'last'}}>Last</th>
So the sort class would always be on, and the current-sort would only be there if it match its proper flag.
imagine you have a table displaying a list of books (like the index does) and you want to make changes in a column called "Sold" (a checkbox for example).
So once you finish "Checking" the books you have sold, you want to save that in the database. How do you send back that list to the controller and update it?
So, the code is something like this, in the controller:
def aMethod(){
...
[bookInstanceList: myBookList]
}
In the GSP:
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "author")}</g:link></td>
<td><g:checkBox name="sold" value="${bookInstance?.sold}" /></td>
<td>
</tr>
</g:each>
The idea is with the checkbox let the user change the "Sold" value from that book. How can I save my new bookInstanceList?
Thank you very much
From what I see you want to dynamically update the backend as the user clicks the check box?
If so then you need an ajax call something like this would do it:
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "author")}</g:link></td>
<td><g:checkBox name="sold" value="${bookInstance?.sold}" onChange="TriggerFilter(this)" /></td>
<td>
</tr>
</g:each>
<g:javascript>
function TriggerFilter(e) {
if (e.checked==true) {
$.get('<g:createLink action='Your_Action' controller="YourController"
params="[ filterbind: ''+attrs.filterbind+'',term:''+attrs.term+'' ]"/>'
,function(data){
$('#FilterField').hide().html(data).fadeIn('slow');
});
}else{
$('#FilterField').hide().html('').fadeIn('slow');
}
}
</g:javascript>
<div id="FilterField" class="filterField">
{Result returned in here}
</div>
You need to fit it e.value into the params take a look at grails java script get createLink there are lots of examples in my plugin here:
https://github.com/vahidhedayati/ajaxdependancyselection/tree/master/grails-app/views
and I would suggest looking online/reading on how to use it
You may wish to change the get to :
how to use grails ${createLink} in javascript
var url = '${createLink(controller:'Books', action: 'update')}' + e.value ;
$.get(url ,function(data){
$('#FilterField').hide().html(data).fadeIn('slow');
});
}else{
$('#FilterField').hide().html('').fadeIn('slow');
}
}
I came accross a wierd situation, using Ember and Handlebars. I have a table of records. The user should click to any record and be redirected to the item detail - quite a usual use case.
However, Ember does not renders the link correctly. It works when I wrap only a single word or element by linkTo tag, but it does not work when I wrap whole table row.
{{#each item in controller.content}}
{{#linkTo "detail" item}}
<tr>
this is part of the link, correctly
<td>and this is not</td>
<td>{{item.someInfo}}</td> <!-- this neither -->
</tr>
{{/linkTo}}
{{/each}}
How can I fix this, when I want whole tr to work as a link?
Tables should only have <tr> fields in them, and <tr> fields should only have <td> fields in them. You're trying to add an ember tag (and an anchor) outside the table row, which shouldn't be done in a table.
If you want something done when clicking a table, rather add an action to the row. Something like the following should work.
<tr {{action 'details' on="click"}}>
details will, of course, be a function in the corresponding controller from where you can transition to wherever you like.
I am using Ember.js to create a table from a json feed. I have a requirement to flash the values (within a table row) that are changing. How do I do this in Ember.js?
My template is shown below:
<tbody>
{{#each Quotes.quotesController.content}}
<tr>
<td class="quote-name">{{name}}</a>
<td class="quote-code">{{code}}</a>
<td class="quote-value">{{value}}</a>
<td class="quote-bid">{{bid}}</a>
<td class="quote-offer">{{offer}}</a>
</tr>
{{/each}}
</tbody>
Here's the code that fetches and updates the quotes:
fetchQuotes: function() {
var scope = this;
$.getJSON('/rest/quotes', function(data) {
$.each(data, function(index, quote) {
scope.updateQuote(quote);
});
});
}
Just as a comparison, in backbone.js, I was binding to change events at the attribute level and firing animations in the callbacks. For example:
this.model.bind('change:value', this.updateValue);
updateValue: function() {
var td = $(this.el).children('.quote-value');
td.html(this.model.get('value'));
td.animate({color: animationColor}, 200)
.animate({color: '#000000'}, 3800, 'easeInQuint');
},
I don't know if such an approach is possible/recommended using Ember.js.
Edit:
I almost have it now. I can handle an event on a table cell and change its color to anything. See this jsfiddle - click of any cell in the value column and it will turn red. The only thing I don't know is how to capture a change to the table cell value instead of a click event. Is there any such thing as a change event that I can capture?
See the following jsFiddle (a modification of an answer another one of your questions). I think from there you can do what you need, but in short you need to make an observer that watches for changes to the property on your controller that is holding the array that you are modifying.
Edit in response to the 1st comment:
Here is a working solution in response to that comment: http://jsfiddle.net/ud3323/ykL69/