'How to Create a Dropdown Menu with Static Items in Ember

I'm very new to JS/Ember and have been able to create a static dropdown menu that functions as desired however I've duplicated the static array of objects that holds the dropdown items in my model and controller which violates DRY.

There are two routes (index and requests/new) that need to access this static array object (reasonList) that holds the dropdown items - one has a model and controller (requests) and the other (index) only has a controller. My understanding is that controllers can read from models but not vice versa so it seems like the model is the correct place for this static array object. I've tried many different ways to resolve this but none have succeeded so instead I'm just asking what the right way to do this is.

ember-cli version: 3.15.1
node version: 10.18.0
ember-source version: 3.3.2

models/request.js:

import { belongsTo } from 'ember-data/relationships';
import Model from 'ember-data/model';
import DS from 'ember-data';

export default Model.extend({
  // Properties
  reason_bucket: DS.attr('string'),
  reason: DS.attr('string'),
  approved_at: DS.attr('number'),

  reason_label: computed('reason_bucket', function() {
    let reasonList = [
      { value: "testDebug", label: "Test & Debug" },
      { value: "auditSupport", label: "Audit Support" },
      { value: "incidentResponse", label: "Incident Response / Case Support" }
    ]

    return reasonList.findBy('value', get(this, 'reason_bucket')).label;
  }), // snip

controllers/requests/new.js:

import lookupValidator from 'ember-changeset-validations';
import Changeset from 'ember-changeset';
import {computed, get, set} from '@ember/object';
import Controller from '@ember/controller';
import SearchAccountsMixin from '../../mixins/search-accounts';

export default Controller.extend(SearchAccountsMixin, {
  init() {
    this._super(...arguments);
    this.clear();
    this.reasonList = [
      { value: "testDebug", label: "Test & Debug" },
      { value: "auditSupport", label: "Audit Support" },
      { value: "incidentResponse", label: "Incident Response / Case Support" },
    ];
  },

  clear() {
      set(this, 'reason_bucket', null);
  },

  selectedReason: computed('reason_bucket', function(){
    return this.get('reasonList').findBy('value', this.get('reason_bucket'));
  }),

  actions: {
    setSelectedReason(selectedVal){
      this.set('reason_bucket', selectedVal.value);
      get(this, 'changeset').set('reason_bucket', selectedVal.value);
    }, // snip

    submit(changeset) {
      changeset.validate().then(() => {
        if (changeset.get('isValid')) {
          changeset.save().then(() => {
            this.transitionToRoute('index')
          })
        }
      })
    }
  },

  // Computed properties
  changeset: computed('model', function () {
    return new Changeset(get(this, 'model').request, lookupValidator(AccessRequestValidator), AccessRequestValidator, {skipValidate: true});
  }), // snip

templates/requests/new.hbs:

<div class="omitted">
    {{#power-select
      options=reasonList
      searchField="label"
      placeholder="Select a Reason for Access"
      selected=selectedReason
      onchange=(action 'setSelectedReason')
    as |reason_bucket|
  }}
    {{reason_bucket.label}}
  {{/power-select}}
  {{group.errorsList}}
</div>

templates/index.hbs:

<div>
  <div class="b">Reason </div>
  <div>{{request.reason_label}}</div>
</div>
<div>
  <div class="b">Reason Detail </div>
  <div>{{request.reason}}</div>
</div>


Solution 1:[1]

If what you’re wanting to do is DRY out your list and find a good home for it, I’d suggest putting your array (and possibly search functionality in a utils file - which doesn’t exist but which you can create and import from). Then you’d be able to do something like:

// app/utils/reasonList.js
export const reasonList = [];


import { reasonList } from ‘appName/utils/reasonList’;

selectedReason: computed('reason_bucket', function(){
return reasonList.findBy('value', this.get('reason_bucket'));
  }),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 acorncom