# Reuse a component for display and create actions

**URL:** <https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668>\
**Category:** Questions\
**Created:** [April 30, 2018, 9:42am UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668 "2018-04-30T09:42:28Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![belgoros](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/belgoros/32/16101_2.png) [@belgoros](https://discuss.emberjs.com/u/belgoros)\
**Post date:** [April 30, 2018, 9:42am UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668/1 "2018-04-30T09:42:28Z")

</div>

I have a component that I call from a `for` loop in a template and use just to display a model values:

```auto
# templates/holiday_hours.hbs

<form {{action "updateHolidayHours" on="submit"}}>
      {{#each model as |holidayHour|}}
        {{holiday-row holiday=holidayHour}}
      {{/each}}
...

```

Like this, I display several rows with values to update. I’d like to make it possible to a create a new row and reuse the same component template.

Here is the template code

```auto
<form {{action "updateHolidayHours" on="submit"}}>
      {{#each model as |holidayHour|}}
        {{holiday-row holiday=holidayHour}}
      {{/each}}

      {{#if isAddingHoliday}}
        <form {{action "createHoliday" on="submit"}}>
          {{#holiday-row holiday=model}}
            <div class="form-check sm-2">
              <button type="button" type="submit" class="btn btn-success btn-sm">
                <span class="oi oi-plus"></span>
                {{t 'buttons.add'}}
              </button>
            </div>

            <div class="form-check ml-sm-2">
              <button type="button" class="btn btn-danger btn-sm" onclick={{action "cancelAddHoliday"}}>
                <span class="oi oi-x"></span>
                {{t 'buttons.cancel'}}
              </button>
            </div>
          {{/holiday-row}}
        </form>
      {{else}}
        <button type="button" class="btn btn-success btn-sm mb-2" onclick={{action "addHoliday"}}>
          <span class="oi oi-plus"></span>
          {{t 'buttons.new.language'}}
        </button>
      {{/if}}
      <div class="float-right">
        <button type="submit" class="btn btn-success">{{t 'buttons.save'}}</button>
      </div>
    </form>

```

`isAddingHoliday` is a just a flag to flip to indicate if I should display a new row with empty fields or not. Here is how it is triggered in the corresponding controller:

```auto
# controllers/holiday-hours.js

 import Controller from '@ember/controller';
import { inject as service } from '@ember/service';

export default Controller.extend({
  currentShop: service('current-shop'),
  isAddingHoliday: false,

  actions: {
    addHoliday() {
      this.set('isAddingHoliday', true);
      this.set('model', this.store.createRecord('holiday-hour'));
    },

    cancelAddHoliday() {
      this.set('isAddingHoliday', false);
    }
  }
});

```

I tried to call

```auto
 this.set('model', this.store.createRecord('holiday-hour'));

```

But it erased my previously loaded model values. Here is how it looks before clicking on `New holiday` button:

 ![before](https://us1.discourse-cdn.com/flex019/uploads/emberjs_public/original/2X/2/2f39227c3ad0f3958229beec07b580f5030c62a0.png)

Here is what it looks like after clicking on `New holiday` button:

 ![adding](https://us1.discourse-cdn.com/flex019/uploads/emberjs_public/original/2X/e/e0f92d3da242f3c81e636d2b932be00c10e7d5a3.png)

Here is what it looks like after clicking on `Cancel` button:

 ![cancelled](https://us1.discourse-cdn.com/flex019/uploads/emberjs_public/original/2X/c/cd2073c5b8959360b819504a1801c41efeb4bd63.png)

The `model` hook in the route handler is very basic:

```auto
#routes/holiday-hours.js
...
model() {
    return this.store.query('holiday-hour', { shop_id: this.get('currentShop.shop').get('id')});
  },

```

What is the right way to do that ? Thank you.

---

<div class="post-metadata">

**Author:** ![rwjblue](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/rwjblue/32/9411_2.png) [@rwjblue](https://discuss.emberjs.com/u/rwjblue)\
**Post date:** [April 30, 2018, 2:10pm UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668/2 "2018-04-30T14:10:08Z")

</div>

You are replacing the query result (from your routes model hook) with a single newly created record inside `addHoliday`. This is why the previous items are being replaced.

One option would be to stash the temporary holiday-hour record on some other property (e.g. don’t clobber `model`)…

---

<div class="post-metadata">

**Author:** ![belgoros](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/belgoros/32/16101_2.png) [@belgoros](https://discuss.emberjs.com/u/belgoros)\
**Post date:** [April 30, 2018, 2:24pm UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668/3 "2018-04-30T14:24:09Z")

</div>

Thank you for your response. That’s what I was almost sure in. I wonder what is the right way to reuse (if possible) a component in such a case ? I’ve never heard about

> stash the temporary holiday-hour record on some other property

Or may be one of the right solutions would be to create a separate nested route `holiday-hours/new` ? …

---

<div class="post-metadata">

**Author:** ![belgoros](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/belgoros/32/16101_2.png) [@belgoros](https://discuss.emberjs.com/u/belgoros)\
**Post date:** [May 2, 2018, 9:48am UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668/4 "2018-05-02T09:48:41Z")

</div>

I tried to assign `this.store.createRecord('holiday-hour'));` to a new variable in the `init` method of the controller:

```auto
controllers/holiday-hours.js

export default Controller.extend({
  currentShop: service('current-shop'),
  isAddingHoliday: false,
  newHoliday: null,

  actions: {
    addHoliday() {
      this.set('isAddingHoliday', true);
      this.set('newHoliday', this.store.createRecord('holiday-hour'));
    },

    cancelAddHoliday() {
      this.set('isAddingHoliday', false);
      this.set('newHoliday', null);
    }
  }
});

```

Then in the template, I just pass in `newHoliday` to the component:

```auto
#templates/holiday-hours.hbs

{{#if isAddingHoliday}}
        {{#holiday-row holiday=newHoliday}}
          <div class="form-group row">
            <div class="col-sm-2">
              <button type="button" type="submit" class="btn btn-success btn-sm" {{action 'createHoliday' holiday}}>
                <span class="oi oi-plus"></span>
                {{t 'buttons.add'}}
              </button>
            </div>

            <div class="col-sm-2">
              <button type="button" class="btn btn-danger btn-sm" onclick={{action "cancelAddHoliday"}}>
                <span class="oi oi-x"></span>
                {{t 'buttons.cancel'}}
              </button>
            </div>
          </div>
        {{/holiday-row}}

      {{else}}
        <button type="button" class="btn btn-info btn-sm mb-2" onclick={{action "addHoliday"}}>
          <span class="oi oi-plus"></span>
          {{t 'buttons.new.holiday'}}
        </button>
      {{/if}}

```

But it does not work because all the values of the submitted form are null. ☹

```auto
#routes/holiday-hours.js
...
actions: {

    async createHoliday(holiday) {
      var route = this;
      var controller = this.get('controller');

      let newHoliday = this.store.createRecord('holiday-hour', {
        shop: this.get('currentShop.shop')
      });

      console.log('newHoliday: ' + newHoliday);

      try {
        await newHoliday.save();
        route.get('flashMessages').success(route.get('i18n').t('flash.holiday.added'));
        route.refresh();
      } catch(response) {
        let error = response.errors[0];
        if (error.status !== "422") {
          route.get('flashMessages').danger(error.message);
        }
      }
    },

```

---

<div class="post-metadata">

**Author:** ![belgoros](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/belgoros/32/16101_2.png) [@belgoros](https://discuss.emberjs.com/u/belgoros)\
**Post date:** [May 2, 2018, 12:16pm UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668/5 "2018-05-02T12:16:31Z")

</div>

I’getting closer to get it work. I managed to have all the vales submitted but one, - `state`. Here is how the states drop-down list is implemented in the template:

```auto
# templates/components/holiday-row.hbs

<select class="form-control" onchange={{action "selectState" value="target.value"}}>
      {{#each states as |state|}}
        <option value={{state.id}} selected={{eq state.id holiday.state}}>{{state.name}}</option>
      {{/each}}
 </select>

```

where `states` come from `constants` service:

```auto
# services/constants.js
import Service from '@ember/service';
import { inject as service } from '@ember/service';

export default Service.extend({
    i18n: service('i18n'),

    init() {
      this._super(...arguments);
      this.set('states',
        [
          {id: 'open', name: this.get('i18n').t('states.open')},
          {id: 'closed', name: this.get('i18n').t('states.closed')},
          {id: 'divided', name: this.get('i18n').t('states.divided')}
        ]
      );
...

```

I guess that it is because of `state` value is not bound to the model that I don’t get its value ☹So how is it possible to:

- display all states values available as constants
- bind a state value to the state of the holiday.

---

<div class="post-metadata">

**Author:** ![belgoros](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/belgoros/32/16101_2.png) [@belgoros](https://discuss.emberjs.com/u/belgoros)\
**Post date:** [May 2, 2018, 2:02pm UTC](https://discuss.emberjs.com/t/reuse-a-component-for-display-and-create-actions/14668/6 "2018-05-02T14:02:52Z")

</div>

I figured out how to achieve that. I just set the state in `init` action of the `holiday-hours.js` controller:

```auto
# controllers/holiday-hours.js

actions: {
    addHoliday() {
      this.set('isAddingHoliday', true);
      this.set('newHoliday', this.store.createRecord('holiday-hour', {
        state: 'open'
      }));
    },

```
