• If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • Finally, you can manage your Google Docs, uploads, and email attachments (plus Dropbox and Slack files) in one convenient place. Claim a free account, and in less than 2 minutes, Dokkio (from the makers of PBworks) can automatically organize your content for you.


DataStore-Using Records

Page history last edited by Remy Munch 11 years, 1 month ago

In the last section you learned some details about how records are structured and the various states they can transition to.  While it is important to understand how all of this works, normally you can simply work with records using some high level methods and let the underlying machinery do its work.  


This section will explain the common actions you can take when working with individual records.


Loading Records


You can retrieve any individual record from a store if you know the record type and ID.  To get the record, just use the SC.Store#find() method:


var contact = MyApp.store.find(MyApp.Contact, “1”);


Whenever you find a record instance like this, the store will return the record instance immediate if it already exists.  If the record does not exist yet, the store will ask the data source to retrieve the record from the server.  If the data source indicates that it can retrieve the record (even if it hasn’t done so yet), then find() will return a new record instance anyway; usually in the BUSY_LOADING state.


For data sources that actually retrieve the data from the server asynchronously (usually the case for all data sources except for fixtures), the record will automatically transition to the READY_CLEAN state whenever the data arrives.  The record will also notify any property observers that the record attributes have changed.


In general, you do not need to worry specifically about whether a record is ready or loaded when you first retrieve it.  If you use normal controllers, bindings, and observers in SproutCore to monitor property changes, they will all update as appropriate anyway.


If you are planning to display this record in your UI however, in a way the user can edit it, you may want to setup your UI to observe the ‘isEditable’ property on the record instance.  This property automatically changes from NO to YES when the record is loaded and ready for use.  While isEditable is NO, you should disable any controls for editing.


Note that normally you will load records indirectly by accessing them through relationships rather than using find() directly.  For example, if a Contact has a toOne relationship to a Group, then contact.get(‘group’) will indirectly load the Group record.    Indirect access in this way boils down to a find() call anyway so the above information holds for relationships as well.


Note also that a data source can push data into a store at any time.  If the data source has already loaded data into the store, it will not be loaded again.  To refresh an already loaded record you need to call refresh().


Refreshing Records


Once you have retrieved a record instance, you can refresh its contents from the server at any time by calling SC.Record#refresh().  This method will place the record in a BUSY_REFRESH state and ask the data source to reload the data.  If the record is already refreshing (or loading), this method will have no effect, so it is safe to call at any time.


Since the records you find in the store are only loaded from the server, if needed, one common way to get a record and ensure it is up-to-date from the server is to chain refresh() with find() like so:


var contact = MyApp.store.find(MyApp.Contact, “1”).refresh();


This will retrieve the record and then refresh it if necessary.  Since refresh() returns the record itself, you can safely chain in this way.


Creating Records


To create a new record, you need to use the SC.Store#createRecord() method.  It is important to use this method instead of simply using SC.Record.create() because record instances are managed by the store they belong to.


The createRecord() takes one required parameter and an optional one.  You must pass the record type of the record you want to create as the first parameter.  Simply passing this will return a new empty record that you can populate.  Optionally you can also pass a data hash that will be used as the starting point for the record. 


var contact = MyApp.store.createRecord(MyApp.Contact, { 

  firstName: “John”, lastName: “Doe” 



If you do not provide an ID for the record, the data source is expected to provide the ID when you save it.  Until a record has an ID you cannot add it to record relationships such as toMany().


Once a record is created, it will be in the READY_NEW state.  You can continue to make changes until you are ready to create the record on the server.  At that point you must commit the changes by calling SC.Store#commitRecords().  See the section below on commitRecords() for more info.


Modifying Records 


Once you have a record instance, either by retrieving it or creating it, you can modify the record easily by simply setting properties directly on the record.  A record in the READY_CLEAN state automatically becomes READY_DIRTY when you make changes to it.  New records are already considered dirty until they are created on the server so changes will not effect the status.


Note that SC.Record only knows how to track changes for direct properties on a record or changes to the contents of toMany() relationships.  It does not know how to track changes on nested objects.


For example, if the value of a property is a data hash, replacing the data hash with a new copy will properly dirty the record.  Simply changing a property on the hash itself will not.


var contact = MyApp.store.find(MyApp.Contact, “1”);

var hash = contact.get(‘info’);


// WRONG; does not change contact state

hash.location = “bar”;


// RIGHT: actually changes property on the contact

hash = SC.copy(hash);

hash.location = “bar”;

contact.set(‘info’, hash);


Most of the time this will not be an issue since most properties you exchange will be simple ones like Strings, Numbers, Booleans and toOne() or toMany() relationships.  These are all handled properly by SC.Record.


Once you modify a record, to actually save the changes to the server you will need to call SC.Store#commitRecords().  See the section below on commitRecords() for more info.


Destroying Records


Once you have retrieved a record, you can destroy it at any time by simply calling SC.Record#destroy().  Once a record is destroyed you will not be able to make further changes to it unless the data source “resurrects” it by push new content or returning an error.


Note that the data source can also “push” a destroy onto any clean record at any time (such as if it receives a notification from the server that a particular record has been deleted).  When this happens the state of the record will change and all observers will be notified.


When you destroy a record in memory, you must call SC.Store#commitRecords() to actually save the change to the server. See the section below on commitRecords() for more info.


Committing Changes to the Server


Normally changes you make to a record remain in memory only until you decide to commit them back to the server via the data source.  You commit changes for your store using the SC.Store#commitRecords() method.  


(NOTE: This method only works on the master store.  Nested stores cannot commit directly to the server; only to their parent store.  See the section on nested stores for more info.)


The DataStore framework keeps track of which records have changed in your store and need to be committed to the server.  You can often simply call commitRecords() on a store with no parameters to commit any changed record automatically.  In some cases, you may want to control specifically which records you want to commit.  In this case, simply pass an array of record types and array of ids for the records you want to commit.


Usually the design of the store is such that you would be expected to call commitRecords() immediately after you have finished making a change.  For example, creating a new contact might involve code like the following:


var contact = MyApp.store.createRecord(MyApp.Contact);

contact.set(‘firstName’, “John”);

contact.set(‘lastName’, “Doe”);

MyApp.store.commitRecords(); // send to server


The store also has an optional commitRecordsAutomatically property that you can set to YES.  In this case, the store will call commitRecords() at the end of each RunLoop automatically if there are any changes pending.


Moving On 


Start finding records on your own with Your First Find » 

or return to DataStore Programming Guide Home »

Comments (0)

You don't have permission to comment on this page.