Today we are going to look at creating and up dating records with Ember. We are going to be using our School Directory App that we have been iterating on for a while now. If you haven't already start by cloning that repo and getting it running locally. If you have already been building out that repo in the past week, it might still be helpful to update it as I had to add a few preliminary items in preparation for setting up editing (really just a few styles and a mirage route for PATCH).

Let's get started.

ember s

Now we can visit our site just to re-familiarize ourself with it. What we are going to want to do first in create the ability to edit an athlete. Let's do this by first creating an edit route that is a child of contacts.contact route.

ember g route contacts/contact/edit

Now, let's pull our additionalInformationComponent out of the contact-card component and put it in our contact controller and template.

First, let remove the component from the contact-card template. In app/templates/components/contact-card.hbs remove {{component additionalInformationComponent contact=contact}} and paste that in app/templates/contacts/contact.hbs. And in the contact template we will change the contact=contact to contact=model. Then we need to move the additionalInformationComponent computed property from app/components/contact-card.js to app/controllers/contacts/contact.js. Here again we will change any occurrence of contact to model.

import Ember from 'ember';

export default Ember.Controller.extend({
  additionalInformationComponent: Ember.computed('model.isTeacher', function(){
    if(this.get('model.isTeacher')){
      return 'past-education';
    } else {
      return 'current-courses';
    }
  })
});

Now if we look back at our site at http://localhost:4200 everything is working again. One final preliminary: we need to move our contact card into the contact/index template at app/templates/contacts/contact/index.hbs. And finally add an outlet to app/templates/contacts/contact.hbs.

Now, we are ready to start implementing our edit. The first thing to note, if you don't specify a model on a route, it gets its parents model. So for index and edit we don't need to specify the model as we already have it on the contact route. To edit our model we are going to use an addon from Dockyard called ember-changeset. There is a link in the episode script. This addon, which is inspired by Elixir's database wrapper, ecto, allows us to edit a contact without making changes directly on the model. This can prevent our model from being placed in a dirty state while editing, and it makes rollbacks a lot easier. It would also allow us to validate our changes before they get set on the model. We aren't going to do validations today, but we can in the future.

We will start by installing the addon. And generating an edit component.

ember install ember-changeset
ember g component edit-card

Now we should restart our server so we can have access to the changeset helper that we will use.

Then let's open up out edit template and add our newly created component. As we are going to be using the changeset addon we will have a few actions that we will call from our component:

app/templates/contacts/contact/edit.hbs

{{edit-card changeset=(changeset model)
            submit=(action "submit")
            rollback=(action "rollback") }}

Now, in our edit controller, let's go ahead and set up our actions for saving and rolling back our edit changes. Open up app/controllers/contacts/contact/edit.js: Let's create a submit action that will take a changeset as the param, and will call save on that changeset. and transition back to the contacts/contact/index route. Then, let's add a rollback action which just calls rollback on the changeset.

import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    submit(changeset) {
      return changeset.save().then(()=>{
        this.transitionToRoute('contacts.contact.index');
      });
    },
    rollback(changeset) {
      return changeset.rollback();
    }
  }
});

Now, we can set up our component. First, let's give our component a class of card and a class edit-card.

import Ember from 'ember';

export default Ember.Component.extend({
  classNames: ['card', 'edit-card']
});

All that is left is for us to set up our component's template.

Then let's open up our component's template and setup our edit form.

{{link-to 'back to contact' 'contacts.contact' class='pull-right'}}
<form>
  <div class="form-group">
    <label>First Name: </label>{{input class="form-control" value=changeset.firstName}}
  </div>
  <div class="form-group">
    <label>Last Name: </label>{{input class="form-control" value=changeset.lastName}}
  </div>
  <div class="form-group">
    <label>Email: </label>{{input class="form-control" value=changeset.email}}
  </div>
  <div class="form-group">
    <label>Phone: </label>{{input class="form-control" value=changeset.phone}}
  </div>
  <div class="form-group">
    <label>Title: </label>{{input class="form-control" value=changeset.title}}
  </div>
  <div class="form-group">
    <label>Avatar: </label>{{input class="form-control" value=changeset.avatar}}
  </div>


  <button class="btn btn-primary" {{action submit changeset}}>Submit</button>
  <button class="btn btn-primary" {{action rollback changeset}}>Rollback</button>
</form>

One last thing. In our contact-card template we need to add a link to our edit form. At the bottom of the template in app/templates/components/contact-card.hbs just add:

{{link-to 'Edit' 'contacts.contact.edit'}}

That does it, we now have a working edit form. Tomorrow we will look at validating our edits.