Series: CRUD 2016

CRUD 2016 pt 2-Read, Update, and Destroy

Published on Feb 24, 2016

Last episode we started our updated CRUD app, connected it to the server, and displayed an array of data. In this episode we take that base and use it to build out 3 of the 4 CRUD operations- Read, Update, and Destroy.

Some topics of interest to contrast with 2015 are route vs resource, controllers (the fact that yes, we’re still using them), es6 methods, the findRecord method, and one-way inputs.

Update: Those using Ember 2.3.1 or later no longer need to use the ember-one-way-controls addon and can use plain handlebars inputs instead.


Links

Code

//routes.js
Router.map(function() {
  this.route('monsters', function(){
    this.route('monster', {path: ':monster_id'}, function(){
      this.route('show')
      this.route('edit')
    })
  })
});
//routes/monsters/monster.js
import Ember from 'ember';

export default Ember.Route.extend({
  model(params){
    return this.store.findRecord('monster', params.monster_id)
  }
})
{{! templates/monsters.hbs }}
...
<div class="row">
  <div class="col-sm-4 col-xs-6">
    <ul class="monsters-index-list">
      {{#each model as |monster|}}
        {{#link-to 'monsters.monster.show' monster  tagName='li' class="monster list-unstyled"}}
          ...
        {{/link-to}}
      {{/each}}
    </ul>
  </div>
  <div class="col-sm-8 col-xs-6">
    {{outlet}}
  </div>
</div>
//package.json
...
"ember-one-way-controls": "0.4.0",
...
{{! templates/monsters/monster/show.hbs }}
<div class="monster-card">
  <span class="name">{{model.name}}</span>
  <span class="pull-right">Level: {{model.level}}</span>

  <img src={{model.imageUrl}} />
  <br>
  ${{model.price}}
</div>
<button {{action 'destroyCard'}}>Destroy Monster</button>
{{#link-to 'monsters.monster.edit' model tagName="button"}}Edit Monster{{/link-to}}
//controllers/monsters/monster/show.js
export default Ember.Controller.extend({
  actions: {
    destroyCard(){
      this.get("model").destroyRecord().then(()=>{
        this.transitionToRoute('monsters')
      })
    }
  }
})
//controllers/monsters/monster/edit.js
export default Ember.Controller.extend({
  actions: {
    save(){
      this.get("model").save().then(()=>{
        this.transitionToRoute('monsters.monster.show', this.get("model"))
      })
    }
  }
})

Transcript

Welcome to Part 2 of our three-part series on building a basic CRUD app in Ember. In the last episode, we set up our app and we displayed an index. That’s one manifestation of the R, the Read in CRUD. As a reminder, CRUD stands for Create, Read, Update, and Delete. In this episode, we’ll go over another type of Read, the show page, as well as Update and Delete.

So first, I want to undo a decision I made last time. While for this particular app, setting the path to just / makes sense, I want to do something that is more representative of what you’ll typically be working with. So we'll just be setting everything within the route monsters.

And so now we’ll have to go to monsters in order to see what we saw before. So within this, we’ll do nested routes. So this first route will just be monster. And then under that we’ll have a show route and an edit route. We’ll also have to make sure to specify this path and give it the monster id.

As I mentioned last time, now we just use routes. There are no calls to resource. And I want to talk a little bit about some of the implications of that. So now the route to show instead of monster.show, it’s monsters.monster.show, and we'll be seeing that when we link to it.

And when we make the files, they’ll be nested all under monsters. So here we’re creating the monster route, and the model we’ll give it will be taking in params, and then we’ll grab the store and then use findRecord on the store. We’ll pass it two arguments. One, the name of the model, monster in this case, and then the second is the id that we get from the params. And then of course we have to return the whole thing. Now let’s make sure that it shows up correctly.

So first we’ll go to monsters. Why are we going here? Well right now we don’t have an outlet, so we’re going to stick an outlet here. The outlet is where you display what’s in the nested route. So going back to our router, all this in here is displayed within this outlet. We’ll go ahead and create a simple route for monster show to demonstrate this.

Here we can see that the “HI!” that we put here is being nested all the way in here, so through this outlet. And then since we haven’t defined a monster.hbs listed under monsters, then it’s automatically just an outlet.

So we have our show page. Let’s do a little bit of something with it. We’ll go ahead and put in model.name. So that’s going to give us the name of the monster. And then in our monsters.hbs, let’s make one of these things a link.

So we’ll turn this list item into a link-to helper. So we’ll make sure the tagName is listItem, and then we’ll feed it the class same as before, and make sure to change the closing tag. And of course we have to link-to something. So we’ll link to monsters.monster.show, and then we’ll give it the monster. And as you can see it’s working. We have the name over here and then it changes, as does the URL, when we click on any of our links. And then with a snap we’ll add in a bunch of styling.

So that completes the Read portion of CRUD. In the rest of this episode, we’ll tackle Update and Delete. And we’ll go ahead and do Delete first, since it’s a quick win.

We’ll start off by creating a Delete button, and that Delete button will have an action called destroyCard. We’ll create that action on the show controller, and yes, we’re still using controllers, because routable components is not yet a thing as of time of this recording. So we’ll create the show controller and then the actions hash and then the destroyCard action on it.

In this action, we’re first going to get the model, and then we’re going to call destroyRecord. This will destroy the record, mark it as destroyed, and then save it. And it’s a promise so we can get a then on the promise, and from here we can transitionToRoute. And the route we'll want to go to is monsters, because there’s nothing left of this monster. We want to get far away from here if we can.

So let’s try this out. We will sadly be destroying Spruce Lee, and now he is like water. And even if you reload, he’s still gone. So let’s not test this functionality anymore, there are only so many monsters here, and let’s make our edit functionality.

So this functionality will also start with a button, and this button will say Edit Monster. That’s rather fitting, but instead of being an action, it will be a link. So the tagName will be button. And then what we’re linking it to is monsters.monster.edit, and we’ll feed it the model. When we click this button, it takes us to the edit route. So far so good. Now let’s put something here so we can edit our monster.

To make this happen more efficiently, we’re going to want to pull in the ember-one-way-controls add-on. And this will let us more easily set up one-way bindings. Then we’ll create the edit template and paste in some code with one-way inputs where we’re binding the value and then we’re updating with the mut helper. If you’re confused by this, you can go back to episodes 117 and 118 where it’s explained in more detail.

So this is what we get, and you can see that when we edit this, it’s editing it over here. It may not be the best user experience, but it’s a great indication that the editing is working. Now you just need to have a Save button so we can save all these silent ‘h’s.

The button itself is fairly simple, just a button with an action. Then, that action is going to go onto the edit controller. So we have our save action, and it’s going to get the model and call save, and this save is going to propagate up all these mutations that we’ve been storing on the model. And then after that’s done, we’re going to transition to the route monsters.monster.show, because once you’re done editing, why would you want to stay there. So let’s go ahead and add back these silent ‘h’s to Rhauk’s name, and there we go. And if we reload, those changes have stayed.

Now this episode is getting a little long, and we did accomplish what we set out to do. So I’m not going to make this change now, but in around two weeks, look for a way that we can change this without changing it over here, because that can lead to some confusions, like here it looks like we’ve saved but if we reload, we’ve never actually saved. But that’s for another day.

Let’s look at all we’ve accomplished today. We can click on these links and we can get a show page. So we have two different types of Reading. We can edit the monster, so that’s our Update. And then we can Destroy. So that’s three of the four parts of CRUD.

In the next episode, I’m going to show you how to Create. We’re also going to clean up some of the loose ends that we have laying around. I’ll see you then.

CRUD 2016

Subscribe to our mailing list