Creating, reading, updating, and deleting records with Ember Data

In the previous recipe, we retrieved already existing book data from our mock server and displayed it to the user. Ember Data also has the ability to create, delete, and even update records from the data store. We will be looking at these methods and more.

Getting ready

Just like the previous example, we'll need to install Ember CLI Mirage. Take a look at the previous recipe for instructions on this process. We'll be using the same factories as the book recipe and we'll be adding new methods to add, edit, and delete data.

  1. In the mirage folder, open the config.js file:
    // app/mirage/config.js
    export default function() {
    
        this.get('/books');
        this.get('/books/:id');
        this.put('/books/:id');
        this.post('/books');
        this.delete('/books/:id');
    }

    This will mock our backend and allow us to create, update, and delete data. This is done using the HTTP PUT, POST, and DELETE requests. We'll use this later in our program.

  2. Update the book.js file in the app/mirage folder:
    // app/mirage/factories/book.js
    import Mirage, {faker}  from 'ember-cli-mirage';
    
    export default Mirage.Factory.extend({
    
       title: faker.lorem.sentence,  // using faker
       author() {return faker.name.findName(); },
       year: faker.date.past
    });

    This factory will be used to generate fake data that the Mirage in-memory database will return.

  3. Update the default.js file in the scenarios folder:
    // app/mirage/scenarios/default.js
    export default function( server ) {
    
        server.createList('book',10);
    }

    Every time that the application loads, the server will create 10 book objects.

How to do it...

For this recipe, we'll be adding to the book example that we had in the Understanding the functionalities of Ember Data recipe.

  1. Create a route called new and controller named books:
    $ ember g route new
    $ ember g controller books
    $ ember g controller new
    $ ember g controller application
    

    This will generate the new route and books controller files.

  2. Create a new template for the new route:
    // app/templates/new.hbs
    {{outlet}}
    <b>title: {{input value=info.title size='15'}}</b><br>
    <b>Author: {{input value=info.author size='15'}}</b><br>
    <b>Year: {{input value=info.year size='35'}}</b><br>
    <button {{action 'newText' }}>Submit Changes</button>
    <button {{action 'cancel' }}>Cancel</button><br>

    The new route will be used to add a new book to the repository. In this template, the input helper is used to create three textboxes. Each will be bound to the info property. A button at the bottom will submit the changes to the newText action method. The cancel button will trigger the cancel action.

  3. Update the new.js controller with the new actions for cancel and newText:
    // app/controllers/new.js
    import Ember from 'ember';
    
    export default Ember.Controller.extend({
        info: {},
        actions:{
          newText(){
            let inf = this.get('info');
            let newBook = this.store.createRecord('book',{
              title: inf.title,
              author: inf.author,
              year: new Date(inf.year)
            });
    
          newBook.save().then(()=>{
            this.transitionToRoute('application');
            this.set('info',{});
          },()=> {
            console.log('failed');
          });
          },
          cancel(){
            return true;
          }
    
        }
    });
  4. There is a lot going on here; let's take a look at the newText action first:
        newText(){
          let inf = this.get('info');
          let newBook = this.store.createRecord('book',{
            title: inf.title,
            author: inf.author,
            year: new Date(inf.year)
          });

    In this action, we are getting the info property that was declared earlier. This property is an object that is used to store values from the template. The store has a method called createRecord that takes two arguments. The first argument is the model. The second is the object that we want to store. In this case, we want to add a new book record to the store. We use the inf object to set the title, author, and year.

  5. Using the createRecord method doesn't persist the changes. The save() method is used to persist data back to the server:
        newBook.save().then(()=>{
          this.transitionToRoute('application');
          this.set('info',{});
        },()=> {
          console.log('failed');
        });

    The save method is a promise. It will either succeed or fail. If it succeeds, we use the transitionToRoute method to change the route back to the main application.

    Afterwards, we set the info property back to an empty object. We do this so that the template input helper is cleared of all data. If it doesn't succeed, then we output an error to the console:

        cancel(){
          return true;
        }

    The cancel action returns true. What this means is that instead of the controller handling it, it will be bubbled up to be handled by the route:

    Tip

    REST with Ember

    When using the REST adapter in Ember, the save() method will send a PUT, DELETE, GET, or POST HTTP request to the server. The PUT request will be sent during an update. The DELETE request is used to delete a record. POST is used to add a new record, and the GET request is used to retrieve records. This is done by convention by the Ember REST adapter.

  6. Update the books.hbs template file with a new action to update:
    // app/templates/books.hbs
    {{outlet}}
    <br>
    <b>title: {{input value=model.title size='15'}}</b><br>
    <b>Author: {{input value=model.author size='15'}}</b><br>
    <b>Year: {{input value=model.year size='35'}}</b><br>
    <button {{action 'updateText'}}>Submit Changes</button>
    <button {{action 'cancel'}}>cancel</button>
    <br>

    We've updated the books template to behave differently from our last example. In this example, it will allow us to edit the entries as follows:

    How to do it...
  7. Update the books.js controller to handle the new updateText and cancel actions:
    // app/controllers/books.js
    import Ember from 'ember';
    
    export default Ember.Controller.extend({
        actions: {
          updateText(){
            let book = this.get('model');
            book.set('year',new Date(book.get('year')));
            book.save();
            this.transitionToRoute('application');
          },
          cancel() {
            return true;
          }
        }
    });

    The updateText action gets the current book model, sets the year, and then saves it. Afterwards, it transitions to the application route. If needed, we could handle the error condition if the save promise fails. For the sake of simplicity, we'll leave it as is. The cancel action returns true, which means that it will bubble up to the books route to be handled.

  8. Update the books.js file in the route:
    // app/routes/books.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
        model(params){
          return this.store.findRecord('book',params.book_id);
        },
        actions:{
          cancel() {
            return true;
          }
        }
    });

    The route file is the same as the previous recipe, except now we have a cancel action. This cancel action will be triggered after the controller returns true. By returning true here, the action bubbles up one more time to the application route.

  9. Update the new.js route file:
    // app/routes/new.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
        actions: {
          cancel() {
            return true;
          }
        }
    });

    This file will receive the action from the new controller. It also returns true, which means that the cancel action will be handled by the application route as well.

  10. Update the application route file:
    // app/routes/application.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
        model(){
          return this.store.findAll('book');
        },
        actions: {
          cancel(){
            this.transitionTo('application');
          }
        }
    });

    The cancel action in the application route handles the new and book routes cancel action. In either case, it will transition to the application route. In summary, the bubbling of the action went from the new controller to the new route and finally to the application route. If the cancel action was not included in the controller, by convention, the action will automatically bubble up.

  11. We need to update the application template and add a new option to delete records. Update the application.hbs file with the new delete action:
    // app/templates/application.hbs
    {{#link-to 'index'}}<h2 id="title">Welcome to Ember</h2>{{/link-to}}
    {{#link-to 'new'}}<h5>Add New Book</h5>{{/link-to}}
    
    {{outlet}}
    
    {{#each model as |book|}}
        <br>
        title: {{#link-to 'books' book.id}}{{book.title}}{{/link-to}} <br>
    <a href="" {{action 'delete' book}}>delete?</a><br>
    {{/each}}

    The application will display each book. There is also a delete action button at the bottom of each record that passes in the book record.

  12. Update the application controller to handle the new delete action:
    // app/controllers/application.js
    import Ember from 'ember';
    
    export default Ember.Controller.extend({
        actions:{
          delete(book){
            book.deleteRecord();
            console.log(book.get('isDeleted'));
            book.save();
          }
        }
    });

    The book record has a method called deleteRecord. This deletes the record; however, it doesn't send the HTTP delete request to the server until save() is done. Another method called destroyRecord will delete and save at the same time. For this example, we'll use deleteRecord instead.

  13. Load the Ember server and you'll see a list of records. You can click on each record and delete or edit it:
    How to do it...

    Tip

    Not using Ember Data?

    Ember Data is the preferred method when working with a backend data store. However, it doesn't have to be the only option. When defining model information in a route, you can use Ajax methods or define your own repositories as well. You can use services and inject them throughout your application if needed. This will take a substantial amount of extra work, depending on your setup, but it is an option.

How it works...

Ember Data comes with several adapters that can be used to retrieve data from a backend server. The REST adapter allows the user to make requests to a backend server using HTTP GET, DETETE, PUT, and POST requests. By default, it expects responses in JSON.

The Ember Data store methods allow a user to find, delete, and save records. The Ember save() method triggers a response to the server. Before the save is done, records can be rolled back if needed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset