How can I dynamically set the `selected` attribute

2019-04-13 04:55发布

问题:

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.

回答1:

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



回答2:

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.



回答3:

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>