Use computed property to manage onChange event


#1

I have a select element in every row. I’d like to to implement onChange event so that when I select a specific value in the select drop-down list, the textfield in the same row will be disabled.

Here is how the component template is called from other template:

# templates/working-hours.hbs
{{#each weekdays as |weekday|}}
  <div class="form-group row">
     {{weekday-row weekday=weekday modelDays=model}}
  </div>
{{/each}}

So here is my component:

# templates/components/weekday-row.hbs

<label for="state" class="col-sm-2 col-form-label">{{dayRow.name}}</label>
<div class="col-sm-2">
  <select class="form-control" onchange={{action "selectState" value="target.value"}}>
    {{#each states as |state|}}
        <option value={{state.id}} selected={{eq state.id dayRow.state}}>{{state.name}}</option>
    {{/each}}
  </select>
</div>
<div class="col-sm-2">
  {{input min="08:00" disabled=(eq dayRow.state 1) max="22:00" pattern="[0-9]{2}:[0-9]{2}" type="time" class="form-control" value=dayRow.opens }}
</div>
  <label for="closes"class="col-form-label">{{t 'working.hours.labels.to'}}</label>
<div class="col-sm-2">
  {{input type="time" disabled=(eq dayRow.state 1) min="08:00" max="22:00" pattern="[0-9]{2}:[0-9]{2}" class="form-control" value=dayRow.closes}}
</div>

Here is the corresponding JS component:

# components/weekday-row.js

iimport Component from '@ember/component';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import EmberObject from '@ember/object';


export default Component.extend({
  constants: service(),
  weekday: null,
  state: null,
  opens: null,
  closes: null,
  modelDays: [],
  weekdays: [],
  states: [],
  tagName: '',

  init() {
    this._super(...arguments);
    this.states = this.get('constants.states');
    this.dayRow = this.buildDayRow();
  },

  buildDayRow() {
    let dayRow = EmberObject.create({ name: this.get('weekday.name')});
    let foundDay = this.get('modelDays').findBy('day', this.get('weekday.day'));
    if (typeof foundDay != 'undefined') {
      dayRow.set('state', foundDay.get('state'));
      dayRow.set('opens', foundDay.get('opens'));
      dayRow.set('closes', foundDay.get('closes'));
    } else {
      let closedState = this.get('states')[1];
      dayRow.set('state', closedState.id);
    }

    return dayRow;
  },

  actions: {
    selectState(state) {
      //console.log('selected state: ' + state);
      let selectedRow = this.get('dayRow');
      console.log('dayRow before: ' + selectedRow.state);
      this.get('dayRow').set('state', state);
      console.log('dayRow after: ' + selectedRow.state);
    }
  }
});

I tried to call

 actions: {
    selectState(state) {
      console.log('selected state: ' + state); //TODO
      this.get('dayRow').set('state', state)
    }
  }

But the dayRow has not been updated (sure because it depends on weekday property). I tried to use state as CP, but it changes in every row when I change the value in one of the drop-down lists. What is the correct way to manage such a kind of situation ? Thank you.

P.S. If there are some wrong use of Ember or technics in the above code, any improvements are always welcome :slight_smile:


#2

I figured out how to make it work.

I defined a CP in the component to observe state changes:

# components/weekday-row.js

  isClosed: computed('dayRow.state', function() {
    return this.get('dayRow').get('state') == 1;
  }),

Then I used the above CP in the component template:

#templates/components/weekday-row.hbs
...
<div class="col-sm-2">
  {{input min="08:00" disabled=isClosed max="22:00" pattern="[0-9]{2}:[0-9]{2}" type="time" class="form-control" value=dayRow.opens }}
</div>
  <label for="closes"class="col-form-label">{{t 'working.hours.labels.to'}}</label>
<div class="col-sm-2">
  {{input type="time" disabled=isClosed min="08:00" max="22:00" pattern="[0-9]{2}:[0-9]{2}" class="form-control" value=dayRow.closes}}
</div>

Then in the component onChange action I set the dayRow values:

# components/weekday-row.js
...
actions: {
    selectState(state) {
      this.get('dayRow').set('state', state);
      this.get('dayRow').set('opens', null);
      this.get('dayRow').set('closes', null);
    }
  }

With this in place, when Closed state is selected for one of 7 week days, the corresponding opens/closes text field inputs are disabled and their previous times are cleared.

When other than Closed state is selected, the corresponding opens/closes text field inputs are enabled.

Hope this helps. Once again, any improvements are welcome, I’m getting my first steps with Ember…