Ember 2.x Dynamic Select Dropdowns

Fire

Ember is a front-end framework built in Node.js and compiled with Grunt. While contracted out to use Ember to build a web front-end for an educational startup, we wanted to create a dynamic select drop down from an object. The object needed to be constructed so that the property name was the option value and the property value was the option text. While this may sound basic, documentation was scarce for this task, and examples that were out there and tagged with our Ember version would crash our Grunt routine. Eventually, we were able to piece together enough to complete this task; hopefully our experience will help you on similar projects.

First, a few technical notes: The app is built in Ember 2.2.0 with ember-cli version 1.3.7, so for the purposes of this blog post, those two versions are confirmed working. To find your Ember version, use the Ember Inspector. If you need to know your ember cli version, from your terminal run:

 'ember --version'

Select Drop Downs

We use emberx-select version 2.0.2 to make a language selection drop-down. This is a pretty solid plugin, and works well. The one gotcha is that there is no way to get a #x-select helper's value, so if we want to access it after a form is submitted, we'll have to track its changes as they're made. Let's start with just two languages; in our template.hbs file, we'll add the following code to select between English and Español:

{{#x-select action="selectLanguage"}}
  {{#x-option value='en' selected=true}}English{{/x-option}}
  {{#x-option value='es'}}Español{{/x-option}}
{{/x-select}}

Then we'll need to add an action to our route.js file to track changes to the drop-down. For now, we're storing them in an ember object called 'state.language'. The mechanism we're using to store these is a blog post for another day, but essentially this.state is an object that maintains its state (and properties) between route changes. You'll have to figure out whatever mechanism you're going to use to store data.

import Ember from 'ember';

export default Ember.Route.extend({
  actions: {
    selectLanguage: function(selection, component) {
      this.set('state.language', selection);
    },
  },
});

The selection variable passes the value attribute of each of the #x-option helpers. Now every time we change the drop-down value between English and Español, this action will be called and the state will be saved. 

Making a Dynamic Select Drop-Down

Two languages is okay, I guess, but there are so many languages out there to choose from. If your application needs to support hundreds of languages, then you'll need a lot more options, and you're not going to want to write them out one by one. Furthermore, we'll also be dynamically selecting a previously selected value (or English by default).

First, we need an object of languages which we'll push to the model returned in routes.js. For simplicity's sake, I've abridged the object to just seven properties below, but the actual list of almost 200 languages that we used can be found here. We'll also push a variable where we'll store the current language, which we're still storing in 'state.language' (and again, you'll have to figure out your own mechanism to save states).

import Ember from 'ember';

export default Ember.Route.extend({
  actions: {
    selectLanguage: function(selection, component) {
      this.set('state.language', selection);
    },
  },
  model() {
    let m = {
      languages: languages,
      selectedLanguage: this.getWithDefault('state.language' 'en');
    };
    return m;
  },
});

const languages = {
  om: 'Afaan Oromoo',
  de: 'Deutsch',
  en: 'English',
  es: 'Español',
  fr: 'Français',
  hi: 'हिन्दी',
  zh: '中文 (Zhōngwén)',
};

Once we have a list and an initializing variable, we can make the list appear in our template.hbs file. In Ember 1.x, you could simply use the #each helper to iterate over an object's properties. In Ember 2.0, there was no equivalent to this, but Ember 2.1 brought us the #each-in helper. Unfortunately, there's a catch - the #each-in helper is always unbound, so we recommend only using constants as your collections for the #each-in helper to avoid confusion. In this case, our list of languages won't be changing, so we're safe. We also check our model.selectedLanguage property to select the language stored in our state (or English by default). Finally, we wrap the whole thing in an #x-select helper which will call our action 'selectLanguage' from the last step when the select value is changed.

{{#x-select action="selectLanguage"}}
  {{#each-in model.languages as |index lang|}}
    {{#if (eq index model.selectedLanguage)}}
      {{#x-option value=index selected=true}}{{lang}}{{/x-option}}
    {{else}}
      {{#x-option value=index}}{{lang}}{{/x-option}}
    {{/if}}
  {{/each-in}}
{{/x-select}}

And that's it - now you too can have a dynamically generated select drop-down using Ember. This can be used to select from any constant (or slowly changing) list of options without reinventing the wheel (at least not too much).

Big shoutout to Sean Clark (@optikalefx) from Connect AI for his invaluable help and guidance on this project.

Dan Zinkevich
Dan Zinkevich

Developer

Dan joined Zivtech in June 2015 and has experience with a wide array of open source projects, including custom work for Drupal, Wordpress, Ruby on Rails, and Django. Dan is capable of getting involved in the whole stack and is passionate about finding creative and extensible ways to solve problems.

Related Services

Ready to get started?

Tell us about your project