# How to use a component for new/edit template

**URL:** <https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722>\
**Category:** General\
**Created:** [October 26, 2018, 10:01am UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722 "2018-10-26T10:01:39Z")\
**Posts on this page:** 7\
**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:** [October 26, 2018, 10:01am UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/1 "2018-10-26T10:01:39Z")

</div>

I still can’t figure out how to implement and correctly use a component in case where you need the same form to create or edit a Post, for example? The most difficult part is still calling the right action depending on if it is a new Post (should create) or an existing one (should update). I found it to be so basic and frequent in use that it would be grateful it to be a part of the docs.

Here is Posts `new` template:

```auto
#templates/posts/new.hbs
{{#post-form post=model postAction=(action "savePost")}}
  <button type="submit" class="btn btn-success">Save</button>
{{/post-form}}

```

So here is a component template:

```auto
#templates/components/post-form.hbs

<form>
  <div class="form-row">
    <div class="form-group col-sm-6">
      <label for="title">Title</label>
      {{input type="text" class="form-control" value=post.title}}
    </div>
  </div>
  <div class="form-row">
    <div class="form-group col-sm-6">
      <label for="body">Text</label>
      {{textarea type="text" class="form-control" value=post.body}}
    </div>
  </div>
  <div class="form-row">
    <div class="form-group col-sm-6">
      {{#power-select-multiple
        options=tags
        selected=selectedTags
        searchField="label"
        placeholder="Select some tags..."
        onchange=(action "selectTag")
      as |tag|
      }}
        {{tag.label}}
      {{/power-select-multiple}}
    </div>
  </div>
  <div class="form-row">
    <div class="form-group form-check col-sm-6">
      {{input type="checkbox" name="archived" checked=post.archived}}
      <label class="form-check-label" for="published">Archived</label>
    </div>
  </div>

  {{yield}}
</form>

```

Post form component JS file:

```auto
#components/post-form.js
import Component from '@ember/component';

export default Component.extend({
  tagName: '',

  submit(event) {
    event.preventDefault();
    this.postAction(this.get('post'));
  }
});

```

Here is posts/new route:

```auto
# routes/posts/new.js
import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return this.store.createRecord('post')
  },

  actions: {
    async savePost() {
      var route = this;
      let controller = this.get('controller');

      let post = route.modelFor(route.routeName);
      let selectedTags = controller.get('selectedTags');
      post.set('tag_ids', selectedTags.mapBy('id'));

      await post.save();
      this.transitionTo('posts');
    }
  }
});

```

And finally, `posts/new` controller:

```auto
#controllers/posts/new.js
import Controller from '@ember/controller';
import { A } from '@ember/array';
import EmberObject from '@ember/object';

export default Controller.extend({
  init() {
    this._super(...arguments);
    this.selectedTags = [];
    this.tags = this._dummyTags();
  },

  actions: {
    selectTag(tags) {
      this.set('selectedTags', A(tags));
    },

    savePost() {

    }
  },

  _dummyTags() {
    let foot = EmberObject.create({
      id: 11,
      label: 'Football'
    });
    let voley = EmberObject.create({
      id: 12,
      label: 'Voleyball'
    });
    let handball = EmberObject.create({
      id: 13,
      label: 'Handball'
    });

    let tags = [foot, voley, handball]

    return tags;
  }
});

```

It DOES not work, compilation errors, etc. What is wrong with all that ? What I’d like is just to reuse the same component for creating or editing a Post.

---

<div class="post-metadata">

**Author:** ![skaterdav85](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/skaterdav85/32/18291_2.png) [@skaterdav85](https://discuss.emberjs.com/u/skaterdav85)\
**Post date:** [October 27, 2018, 4:05pm UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/2 "2018-10-27T16:05:15Z")

</div>

Move your `savePost` action from the route to the controller.

---

<div class="post-metadata">

**Author:** ![shull](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/shull/32/16184_2.png) [@shull](https://discuss.emberjs.com/u/shull)\
**Post date:** [October 29, 2018, 8:43pm UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/3 "2018-10-29T20:43:52Z")

</div>

In the code, when you submit the form, you want to call call `post.save()`, regardless of whether it’s a new or existing record. So IMO, the component `submit` action should look like this:

```nohighlight
#components/post-form.js
import Component from '@ember/component';

export default Component.extend({
  tagName: '',
  onSave() {},
  onError() {}, # callers can pass onSave/onError actions to customize behavior
  submit(event) {
    event.preventDefault();
    this.get('post').save().then(this.onSave).catch((response) => {
      # TODO: show errors
      this.onError(response);
    });
  }
});

```

(An example of a “smarter” component, which has some behavior of its own instead of relying on callers to define all actions.)

---

<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:** [October 30, 2018, 10:15am UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/4 "2018-10-30T10:15:04Z")

</div>

Thank you guys ! I moved `save`, `update` actions from the routes to corresponding controllers and it works. The only issue I have is that the list of created items is not refreshed after calling `transitionToRoute`. I have to hit `CMD-R` to see a newly added item.

Here is the code from the controller that saves a new item:

```auto
#controllers/country-events/new.js

actions: {
    async save() {
      let event = this.get('model.event');

      let selectedSports = event.get('selectedSports');
      event.set('sport_ids', selectedSports.mapBy('id'));
      event.set('modifiedBy', this.get('currentUser.user').get('username'));

      await event.save();
      this.get('flashMessages').success(this.get('i18n').t('flash.event.added'));
      await this.transitionToRoute('country-events');
    }
  }

```

And here is the route:

```auto
# routes/country-events.js

model() {
    return this.get('currentShop.shop.country').then(country => {
      return this.store.query('event', { country_id: country.get('id')});
    });
  }

```

What am I missing ? Thank you

---

<div class="post-metadata">

**Author:** ![dknutsen](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/dknutsen/32/16471_2.png) [@dknutsen](https://discuss.emberjs.com/u/dknutsen)\
**Post date:** [October 30, 2018, 2:04pm UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/5 "2018-10-30T14:04:18Z")

</div>

@belgoros this is probably because you are using store.query which returns a static array of results. You’ll need to either [refresh the route](https://www.emberjs.com/api/ember/3.5/classes/Route/methods/refresh?anchor=refresh) when you transition to it from country-events/new OR kick off the query but then actually return `store.peekAll('event')` (which live updates with new records) and then filter that list in a computed property.

---

<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:** [October 30, 2018, 2:17pm UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/6 "2018-10-30T14:17:39Z")

</div>

@dknutsen I don’t see how it is possible to refresh a route fro the controller. What is the more correct way to do that? - modify my `model` hook, something else ? Thank you.

---

<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:** [October 30, 2018, 4:04pm UTC](https://discuss.emberjs.com/t/how-to-use-a-component-for-new-edit-template/15722/7 "2018-10-30T16:04:10Z")

</div>

I found the help on Discord help channel (thanks to @locks)

I had to move the content `routes/country-events.js` route to `routes/country-events/index.js` and remove it completely.
