As we now have some understanding of how a store works, let's see how we can use the store to create and delete a record.
To create a new record, you can use the createRecord
method present on the instance of DS.Store
. In your controller or route, you can get the reference of the store object by calling this.store
. Let's take a look at the following example, to know how to create a record of type book:
var book = this.store.createRecord('book',{ title: "Ember.js Essentials", isbn: "ISBN1", pages: 180, description: "The Essentials required to master Ember.js" });
As you may have figured out, the createRecordfunction
takes in two arguments; the first one is the name of the model object you want to instantiate, which is book
in our case, and the second one being the object with properties set to their values. Normally, the users of your application will be entering these attributes in a form, whose values will be bound to the model attributes.
As you may have noticed, we did not set the relationships of the books here. The ember-data
library currently has one limitation; if you assign any promises to relationships of your object, it doesn't automatically resolve them, and assign the resolved object(s) as the value of the property. So, we need to make sure that the relationships should not be assigned to a promise and hence, the object to which it is assigned should contain actual values.
So, we could do something like the following:
var author = this.store.createRecord("author",{ firstName: "Suchit", lastName: "Puri", bio: "something interesting about me", book: book });
Now, since one book can have more than one author, we modeled it using the has-many relationship. As a result, the author's property becomes an empty array on which we need to insert our author
object, as follows:
book.get("authors").addObject(author);
Similarly, you can create a record for the publisher, and then assign it with a book, which is a many to one relationship, because a publisher can publish many books, but a book will be published by only one publisher. Let's take a look at the following example:
var packt = this.store.createRecord('publisher',{ name: "Packt Publushing", organizationName: "Pact", address: "London" }); packt.get("books").pushObject(book); book.set('publisher',packt);
As you may have noticed by now, a DS.hasMany
relationship results an array being initialized for that attribute. One important thing to note is that the ember-data
library makes the DS.hasMany
attribute as a read-only property. This means that you cannot assign the attribute to a new array. Let's see what happens when you try to set the hasMany
association property, books
, to an array while creating a new publisher record.
var packt = this.createRecord('publisher',{ name: "Packt Publishing", organizationName: "Packt", address: "London", books:[book] });
Doing the above will result in an error cannot set read-only property
.
Let's see how you can delete a record from the store. The DS.Store
maintains a flag isDeletedfor
for every object stored in its cache. When you make a request to delete the record from the cache, the store just sets the flag and then does not return the record in future queries. To delete a record, you just need to call the deleteRecord
method on the object.
Doing book.deleteRecord();
will remove the object from the store and set the isDeletedflag
for the object. To sync the changes to the server, you will have to call the save method on the object, which, if used with the default DS.RESTAdapter
, shall make a DELETE
call /books/{:id}
to the server.
One very important thing to note here is that in both cases of creating a new record and deleting a record, you will have to make a save call on the object to reflect the changes on the server. The save()
method will make an appropriate POST
or DELETE
call, based on the state of the object to the server, to sync the state of the object with the server.
If you are using the DS.RESTAdapter
, once you create a new record and save it to the server, making any further changes to the object will result in a PUT
call to the server. So, if you make any changes to the book object after saving it the ember-data
library, you would make a PUT
call to /books/:id
to update the record and sync it with the server.
Whenever we make a save call to the server to sync the state of the object with that of the server, the save immediately returns a promise object, which is resolved once you get a response from the server. Hence, it is a good practice to use them while saving a record on the server as follows:
book.save().then(function(book){ //Do something useful here }).catch(function(reason){ //handle the error if any });
Till now, we have seen how to create, delete, and update a record in ember-data
, and how to sync the record with the server. Often, you may just want to fetch the records from the server based on some criteria, and then display the list or record and then display the list of records fetched. The ember-data
library provides us with the find
method to help us locate our records.
The find
method takes in two arguments; the first argument is the name of the entity or the model we are looking for. This is a required argument. The second argument is either an ID or an object that describes the query we need to use while finding the record. One very important characteristic of the find
method is that if the record(s) that we are looking for is not found in the store's cache, the find
method will immediately return a promise object instead of the actual object. The actual object is initialized with the values from the server, once the promise is resolved. Let's look at an example to make it clearer.
To look for all the books on the server we shall make a call this.store.find("book")
. This shall get translated into a GET
request to /books
, which returns a list of all the books present on the server.
To just look for all the books in the cache of the store, we make a call:
this.store.all("book")
This command will not make any network calls and only looks for records of type book
in the cache of the store.
Similarly, to search for any record on the server of a specific ID, we make a call:
this.store.find("book",1)
This will result in a network call GET
to /books/1
, which should return the complete book object with ID 1.
To look for a book object by name, we need to pass in the query object as the second parameter to the find method, as follows:
this.store.find("book",{"name":"Ember.js Essentials"})
This will result in a GET
request /book?name='Ember.js Essentials'
made to the server.
Please note that all the URLs mentioned are according to the default convention of DS.RESTAdapter
.
As we learned in Chapter 4, Managing Application State Using Ember.js Routes that a route can override the model hook and return the model object that the templates will bind to. One important thing to note here is that if you return a promise from the model hook of the router, the router will not transition to the route, and render the template till the promise is resolved.
Once you have retrieved or saved a record from the server, you can change its properties in your Ember application. The ember-data
library maintains a flag, called as isDirty
, to check if the record was modified after it was retrieved from the server, as follows:
var book = this.store.createRecord('book',{ title: "Ember.js Essentials", isbn: "ISBN1", pages: 180, description: "The Essentials required to master Ember.js" }); book.save().then(function(book){ console.log(book.get('isDirty')); //False book.set('isbn','new ISBN'), console.log(book.get('isDirty')); //True console.log(book.changedAttributes()); //{isbn:['ISBN1','new ISBN']} });
Once we save a book, then subsequently editing it, like changing any property of the book, will result in setting the isDirty
flag to true.
Another helpful method available on the DS.Model
object is changedAttributes()
. This method will return an object containing the attributes of the model that were changed since the last sync with the server.
18.226.181.57