The Ember guide on binding data attributes says that "If you use data binding with a Boolean value, it will add or remove the specified attribute." I'm trying to use this feature to dynamically set the selected
attributes on <option>
s. I'm finding that I can dynamically set the disabled
attribute, but the selected
attribute is always omitted, no whether the boolean is true or false.
Given this handlebars template:
<option disabled={{false}} selected={{false}}>One</option>
<option disabled={{true}} selected={{true}}>Two</option>
I get the following HTML:
<option>One</option>
<option disabled>Two</option>
Why doesn't selected={{true}}
produce a selected
attribute in the rendered output?
To give a bit more context, I'm following this article on How to do a select in Ember 2.0. Using the method described in that article, I can successfully update the data in the controller when the select onchange
event fires, but the DOM doesn't update to reflect the change.
I've put together this ember-twiddle, which includes two select
elements. One uses select={{bool}}
, which doesn't work the way I want it to. The other uses a long-hand {{#if bool}}...{{else}}...{{/if}}
, which does work but looks terrible.
Thanks to everyone who took the time to post an answer my question. Sonny's comment pointed me in the right direction:
selected
is a property, not an attribute with a value
This was news to me and it sent me down a rabbit-hole of discovery. I found this SO answer to be especially helpful.
When I posted the question, I didn't appreciate the difference between attributes and properties. I was expecting to see the selected
attribute appear in the DOM, but this doesn't happen. I now understand that the selected
property is being correctly set, and the fact that the <option>
tag doesn't appear in the DOM with a selected
attribute is of no consequence.
This code snippet helps to illustrate why I was confused. Both of the resulting <select>
dropdown menus appear the same, with option 2 initially selected. The selected
attribute does not appear in the DOM when it's set using selected={{true}}
, but it does appear in the DOM in the other case:
<select>
<option>1</option>
<option selected={{true}}>2</option>
</select>
<select>
<option>1</option>
<option selected>2</option>
</select>
Here's the same snippet as a Twiddle
You can use a helper which compares you option value to a reference somewhere like
<select onchange={{action "countryChanged" value="target.value"}}>
{{#each countries as |country|}}
<option value={{country.id}} selected={{is-equal country model.address.country_code}}>{{country.name}}</option>
{{/each}}
</select>
Inside your "Helpers" folder (create if not already there)
create your helper file like "is-equal.js"
import Ember from 'ember';
export default Ember.Helper.helper(function([lhs, rhs]) {
return lhs === rhs;
});
Which will just compare 2 values and return a boolean, you could also return a classname or whatever you like.
The action sets the user selected value to the model.address.country_code, the helper compares the new values, if the selected value matches the option value selected will get set to true.
I was able to set the selected option using a variable as seen here: https://gist.github.com/fenichelar/d3cfa5c59783fdbf02d32bcc3b3a028d
Here is the Ember Twiddle: https://ember-twiddle.com/d3cfa5c59783fdbf02d32bcc3b3a028d?openFiles=templates.application.hbs%2C
Relevant Code:
application.js
import Ember from 'ember';
export default Ember.Controller.extend({
one: false,
two: true,
three: false
});
application.hbs
<div>
<select>
<option selected={{one}}>One</option>
<option selected={{two}}>Two</option>
<option selected={{three}}>Three</option>
</select>
</div>