Ember: set attribute's value with action passed from a <select> element - ember.js

I'm trying to figure out how to set a new Ember Data Record's attribute's value based on choices in a select element, using the {{action}} helper. Here's my situation, simplified:
item.js route. Creates a new record that is available in the template.
model() {
return this.store.createRecord('item');
}
new-item.hbs template. The select-element triggers the action to set the new item's color attribute.
<select {{action 'setColor' model value="target.value" on="change"}}>
<option value="">choose</option>
<option value="white">white</option>
<option value="blue">blue</option>
<option value="red">red</option>
<option value="yellow">yellow</option>
</select>
item.js controller.
actions: {
setColor(item, option) {
console.log(option);
record.set('color', option);
console.log(item);
}
}
Console.log(option) returns nothing. The record.set works fine, I can hardcode the option and the console.log(item) will show that the new item object has the color attribute set.
On the other hand, if I do the action call with just
onChange={{action 'setColor' value="target.value"}}
the color gets logged correctly from the action. But if I add "model" into that action call as before with the {{action ... on="change"}} syntax, console.log(option) returns undefined and console.log(item) returns an Event with no model object attached.
Question is: How do I pass both the target.value and the model to the setColor action?

setColor function will receive event attribute as last argument by default.
onChange={{action 'setColor' value="target.value"}}
so value attribute will be retrieved from event. so this will work as expected. but
onChange={{action 'setColor' model value="target.value"}}
value attribute will try to get target.value from model property as we sent model as first argument, and default event argument will be passed as second argument. so combining won't work.
Solution would be
onChange={{action 'setColor' model}}
and inside actions,
actions: {
setColor(model, event) {
let value = event.target.value;
}
}

I just had the same issue, but was not satisfied with the accepted answer here, since I had 2 different inputs (dropdown & text-field) that used the same action (but not same path to resolve the value), so I had to use value="..." as part of the action helper.
I found the answer in https://stackoverflow.com/a/45762071/45948
so in your case it would be:
onChange={{action (action 'setColor' model) value="target.value"}}
and then simply:
actions: {
setColor(model, option) {
...
}
}

Related

How to handle ember checkbox binding

I am new with ember and I have a question about checkbox binding.
Here is my js && hbs :
CompletedToday(id){
var today = new Date().toISOString().slice(0, 10);
this.get('DS').findRecord('menu',id).then((recs) => {
recs.get('completedDates').pushObject(today);
recs.save();
});
},
{{#each menu}}
{{input type="checkbox" checked=this.checkCompleteToday click=(action "CompletedToday" menu.id)}}
{{/each}}
Menu is a model has a attribute called Completed date, which is a array contains a list of dates(YYYY-MM-DD), there should be a constructor function to check if it’s completed TODAY, if it is completed, make the checkbox of that menu as checked. If not, user can check the specific checkbox I don’t know how to handle this actually, do i need to create another attribute for menu?
Any suggestion would be appreciated
First you need a computed property that returns true or false if TODAY is in the model.
you should create in your component a computed property like:
checked = computed('model', function() {
// pseudocode bellow
return (TODAY in array)
})
Now, if it is unchecked (TODAY not in array), you should be able to insert in array.
In you hbs:
{{input type="checkbox" checked=checked click=(action "CompletedToday" menu.id)}}
(you shouldn't use "this" to reference the property)
If "CompletedToday" is in your component actions, it should work.
I hope this helps

How to get the element reference "this" in EmberJS events?

I want to access the target element in the called method in onchange. I have the following code:
Template
<select class="form-control" data-abc="1" onchange={{action 'someMethod' value="target.value"}} >
<option value="">Select</option>
.
.
.
</select>
Component
export default Ember.Component.extend({
actions: {
someMethod(value) {
jQuery(this).data("abc"); // <-- Want to access element here
}
}
});
But, this doesn't work.
When you use value="target.value", someMethod will receive only the value alone and it will not receive default event object.
onchange={{action 'someMethod'}}
your component code would be,
export default Ember.Component.extend({
actions: {
someMethod(event) {
//its event object, you can access event.target to get element or event.target.value to get the value.
}
}
})
I got the answer:
<select class="form-control" data-abc="1" onchange={{action 'someMethod' value="target"}} >
<option value="">Select</option>
.
.
.
</select>
As can be seen in above code, we can pass the target instead of target.value. Then wrap target in jQuery to access desired data attribute.

Load data from database on select box onchange event

Can anyone guide me how to load data from a database when I change the value in the select box? I tried the following code, but when I try to get the "value" and log it says "undefined."
My Component.js
actions:{
filterStudent(){
let filterInputValue = this.get('value');
console.log(filterInputValue);
let filterAction = this.get('filter');
console.log(filterAction);
}
}
My Controller
actions:
{
filterStudentResults(param)
{
if (param !== '')
{
return this.get('store').query('Students', { studentName: param });
}
else
{
return this.get('store').findAll('Students');
}
}
}
My Component.hbs
<select name="newType" onchange={{action "filterStudent" value="target.value"}} class="form-control">
<option value="" disabled selected>Please Select</option>
{{#each model.Students as |newStudents|}}
<option value="{{newStudents.studentId}}">{{newStudents.studentName}}</option>
{{/each}}
</select>
Am calling the component in the Specific template as
{{bind-dropdown model=model Filter=filterStudentResults}}
Am a newbie to EmberJS and appreciate any help. Thanks in Advance :)
In My-Component.js, does not having value as property, You mean to get it from onchange={{action "filterStudent" value="target.value"}} then your action should receive param,
actions:{
filterStudent(selectedValue){
console.log(selectedValue);
}
}
One more problem, I found upon sending action filterStudentResults to component.
The below one is wrong.
{{bind-dropdown model=model Filter=filterStudentResults}}
As you have defined filterStudentResults in controller, you can create closure action and send it to component, so it should be like,
{{bind-dropdown model=model filter=(action 'filterStudentResults')}}
And it should be invoked with selectedValue from component action,
actions:{
filterStudent(selectedValue){
this.sendAction('filter',selectedValue);//this will call controller method with param
}
}
First you need to check the model is ready and you can do so inside route's afterModel(model) hook.
<select name="newType" onchange={{action "filterStudent" value="target.value"}} class="form-control">
Should be re-write to,
<select name="newType" onchange={{action "filterStudent"}} value={{target.value}} class="form-control">
My controller is not getting invoked from the component the sendAction method is not working.
MyController.js
actions:
{
filterStudentResults(param)
{
if (param !== '')
{
return this.get('store').query('Students', { studentName: param });
}
else
{
return this.get('store').findAll('Students');
}
}
}
am calling the component from the template as follows
{{bind-dropdown model=model filter=(action 'filterStudentResults')}}
My Component js
actions:{
filterStudent(selectedValue){
this.sendAction('filterPartsResults',selectedValue)
}
My Componet file name is bind-dropdown and my contollers name is studentsController. The template name is list-studentDetails.

How can I filter Ember.Select content, instead of using {{each}} {{if}} handlebars filtering?

Using the select method with handlebars each and if helpers I can successfully display an array where only those with active = true.
<select>
{{#each content.users}}
{{#if active}}
<option value="">{{firstName}}</option>
{{/if}}
{{/each}}
</select>
vs
{{view Ember.Select class='btn btn-default dropdown-toggle' style='max-width: 200px'
content=content.users
optionValuePath='content.id'
optionLabelPath='content.firstName'
selectionBinding='someSelectionBinding'}}
The downside to the select way is I can't bind an action to the option value, and I lose out on some of the useful Ember Selection binding and label functionality/observers. Where the downside to the Ember.Select way is I can't set my content to only those users who have the active flag.
I'm assuming you're using a recent version of Ember. In your controller, assuming an Ember.ArrayController with content.users defined as you seem to have it, you'll want to create a new attribute, like activeUsers:
App.ThisController = Em.ArrayController.extend({
// Other stuff
activeUsers = Em.computed.filterBy('users', 'active', true)
})
This should give you an array of users where the active attribute is true, so you can set the content of your Ember.Select view to content.activeUsers.

How to set value for input field and have it update on submission to Ember.js action?

On the handlebars template, I'd like to pre-populate an input field with the value. That I can do by putting value=object.property. Then the user should update the value, and when they click the button activating the action, the value should submit to the Component.
The problem is that no value is getting submitted, not the pre-populated value, or the new value. When I console.log what is getting submitted to the component, the input from the text field is "undefined" and the input from the number field is "NaN".
This is my handlebars template:
{{input type="text" value=object.name valueBinding='newName'}}
{{view App.NumberField min='1' value=object.count valueBinding='newCount'}}
<button {{action updateObjectDetails object}}>Save</button>
The related component it is submitting to:
App.ObjectsDetailsComponent = Ember.Component.extend({
actions: {
updateObjectDetails: function(object){
object.set("name", this.get('newName'))
object.set("party_size", parseInt(this.get('newCount')))
object.save();
}
}
});
Is there a way to populate the input field with the correct value AND have it submit with the action?
Ah, got it. The thing is to not try to use the valueBindings, like you might when creating a new object, but to use the actual value, because the actual value is changing. So in the component, it's object.get('name'), not this.get('newName').
Therefore the handlebars should be like this:
{{input type="text" value=object.name}}
{{view App.NumberField min='1' value=object.count}}
<button {{action updateObjectDetails object}}>Save</button>
And the component like this:
App.ObjectsDetailsComponent = Ember.Component.extend({
actions: {
updateObjectDetails: function(object){
object.set("name", object.get('name'))
object.set("party_size", parseInt(object.get('count')))
object.save();
}
}
});