“This is the 18th day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021.”

We introduced Ember Data and Model Definitions of Ember Data in ember.js project Development. This article continues with the recording operation.

Document retrieval

The Ember Data store provides an interface for retrieving a single type of record.

Retrieving a single record

Using store.findRecord() retrieves records based on their type and ID, processing records that meet the search criteria by returning a promise:

// GET /blog-posts/1 this.store .findRecord("blog-post", Then (function (blogPost) {// parse data}); then(function (blogPost) {// parse data});Copy the code

Using store.peekRecord() is based on the type and ID of the record, no HTTP request is made, and the record is returned only if it already exists in the store:

const blogPost = this.store.peekRecord("blog-post", 1); // => No HTTP requestCopy the code

Retrieve multiple records

Use store.findall () to retrieve all records of the specified type:

// GET /blog-posts this.store.findall ("blog-post") // GET /blog-posts. Then (function (blogPosts) {// GET /blog-posts this.store.findall ("blog-post"));Copy the code

Use store.peekall() to retrieve all records of the specified type that have been loaded into the store without making an HTTP request:

const blogPosts = this.store.peekAll("blog-post"); // => No HTTP requestCopy the code

Store.findall () returns a satisfied RecordArray and the PromiseArray of the store, and Store.peekall returns RecordArray directly.

Note that RecordArray is not a JavaScript array, it is an object that implements MutableArray. This is important because, for example, if you want to retrieve records by index, the [] symbol will not work and you must use objectAt(index) instead.

Querying Multiple Records

Ember Data provides the ability to query records that meet certain criteria. Calling store.query() issues a GET request and serializes the passed object into query parameters. This method, like findAll, returns a PromiseArray.

For example, the following retrieves the person named Peter in the Person model:

// GET to /persons? filter[name]=Peter this.store .query("person", { filter: { name: , "Peter,"}}). Then (function (Peters) {/ / parse the retrieved records});Copy the code

Query a single record

If you are using an adapter that supports server requests that can return a single model object, Ember Data provides a convenient method, store.queryRecord(), that returns a promise to resolve that single record. The request is made through the queryRecord() method defined by the adapter.

For example, if the server API provides an endpoint app/adapters/user.js for the currently logged in user:

// GET /api/current_user
{
    user: {
        id: 6188,
        username: "devpoint",
    },
};
Copy the code

If the User model’s adapter defines a queryRecord() method for that endpoint:

import Adapter from "@ember-data/adapter"; import fetch from "fetch"; export default class UserAdapter extends Adapter { queryRecord(store, type, query) { return fetch("/api/current_user"); }}Copy the code

A call to Store.queryRecord () will then retrieve the object from the server:

store.queryRecord("user", {}).then(function (user) {
    const username = user.get("username");
    console.log(`Currently logged in as ${username}`);
});
Copy the code

As in the case of store.query(), query objects can also be passed to store.queryRecord(), and the adapter’s queryRecord() can use query objects to qualify requests. However, the adapter must return a single model object, not an array containing one element, or Ember Data will throw an exception.

Note that Ember’s default JSON:API Adapter does not provide the methods needed to directly support queryRecord(), because it relies on REST request definitions that return result data in array form.

If the server API or adapter only provides array responses, but you want to retrieve only one record, you can also use the query() method, as shown below:

If the server API or adapter only provides array responses, but you want to retrieve only a single record, you can choose to use the following query() method:

// GET to /users? filter[email][email protected] const devpoint = store .query("user", { filter: { email: "[email protected]", }, }) .then(function (users) { return users.get("firstObject"); });Copy the code

Create a record

Records can be created by calling the createRecord() method in the Store.

store.createRecord('post', {
  title: 'Rails is Omakase',
  body: 'Lorem ipsum'
});
Copy the code

You can use the store object this.store in controllers and routes.

Update record

Changing an Ember Data record is as simple as setting the properties to change:

this.store.findRecord('person', 1).then(function(tyrion) { // ... after the record has loaded tyrion.firstName = 'Yollo'; });Copy the code

Continue to record

Records in Ember Data are persisted by instance. Any instance of save() is called, and the Model makes a network request.

Ember Data tracks the status of each record for you. When saved, this allows Ember Data to treat newly created records differently from existing records.

By default, Ember Data adds new records created by POST to its type URL.

let post = store.createRecord('post', {
  title: 'Rails is Omakase',
  body: 'Lorem ipsum'
});

post.save(); // => POST to '/posts'
Copy the code

The existing records on the back end are updated using the HTTP PATCH verb.

store.findRecord('post', 1).then(function(post) {
  post.title; // => "Rails is Omakase"

  post.title = 'A new post';

  post.save(); // => PATCH to '/posts/1'
});
Copy the code

You can determine if a record has unfinished changes that have not been saved by examining its hasDirtyAttributes attribute. You can also use the changedAttributes() method to see which parts of the record were changed and what the original values were. ChangedAttributes returns an object whose key is the changed attribute and whose value is an array of values [oldValue, newValue].

person.isAdmin; // => false
person.hasDirtyAttributes; // => false
person.isAdmin = true;
person.hasDirtyAttributes; // => true
person.changedAttributes(); // => { isAdmin: [false, true] }
Copy the code

At this point, you can either keep the changes or roll them back by saving (). The records saved by the rollbackAttributes() call will restore all changedAttributes to their original values. If there is a record isNew, it will be removed from the Store.

person.hasDirtyAttributes; // => true person.changedAttributes(); // => { isAdmin: [false, true] } person.rollbackAttributes(); person.hasDirtyAttributes; // => false person.isAdmin; // => false person.changedAttributes(); / / = > {}Copy the code

Handling Validation errors

If the backend server returns validation errors after trying to save, those errors will be available on the attributes of the Errors model. This is how the error may appear when saving a blog post in a blog template:

{{#each this.post.errors.title as |error|}}
  <div class="error">{{error.message}}</div>
{{/each}}
{{#each this.post.errors.body as |error|}}
  <div class="error">{{error.message}}</div>
{{/each}}
Copy the code

Promises

Save () returns a promise, which makes it easy to handle successful and failed scenarios asynchronously. This is a common pattern:

let post = store.createRecord('post', {
  title: 'Rails is Omakase',
  body: 'Lorem ipsum'
});

let self = this;

function transitionToPost(post) {
  self.transitionToRoute('posts.show', post);
}

function failure(reason) {
  // handle the error
}

post
  .save()
  .then(transitionToPost)
  .catch(failure);

// => POST to '/posts'
// => transitioning to posts.show route
Copy the code

Delete records

Deleting records is as simple as creating them. Call deleteRecord() on any instance of the model. This marks the record as deleted. The delete can then be persisted using save(). Alternatively, you can use the destroyRecord method to both delete and persist.

let post = store.peekRecord('post', 1);
  post.deleteRecord();
  post.isDeleted; // => true
  post.save(); // => DELETE to /posts/1
});

// OR
  post = store.peekRecord('post', 2);
  post.destroyRecord(); // => DELETE to /posts/2
});
Copy the code