
Retrieving remote data
So far, we have been working with local data, and hard-coding our information to create a store of records. But in real world applications, we will have our data in a database, or maybe we'll get the information using web services.
Ext JS uses proxies to send and retrieve the data to and from the source. We can use one of the available proxies to configure our store or model.
Proxies in Ext JS are in charge of handling the data/information of a data model; we can say that the proxy is a class that handles and manipulates the data (parsing, organizing, and so on), so the store can read and save or send data to the server.
A proxy uses a reader to decode the received data, and a writer to encode the data to the correct format and send it to the source. We have three available readers to encode and decode our data: the Array, JSON, and XML readers. But we have only two writers available; only for JSON and XML.
There are many types of proxies at our disposal. If we want to change our source of data, we should only change the type of proxy and everything should be fine. For example, we may define an Ajax proxy for our store or model, and then we can change it for a local storage proxy.
Ajax proxy
In order to use this proxy, we need to set up a web server to make the Ajax requests correctly. If we don't have a web server to test our code, we can use the WAMP or XAMPP server (see Chapter 1, An Introduction to Ext JS 5). Using a web server is required so that we can make Ajax requests correctly.
When we have everything ready, we can modify our previous example, where we created the Customers
class to add the required proxy.
Ext.define('Myapp.store.customers.Customers',{ extend:'Ext.data.Store', model: 'Myapp.model.Customer', proxy:{ type:'ajax', url: 'serverside/customers.php', reader: { type:'json', rootProperty:'records' } } });
The previous code adds a new property to the store called proxy
. We are setting a configuration object containing three properties. The type
property defines the type of proxy that we're going to use. In this case, we specified ajax
, but we can use any of the available proxies.
The url
property defines the resource that we will request using Ajax. It's important to mention that the URL must be in the same domain so that we 'don't get any errors when making the Ajax request. If you plan to use a cross-domain URL then it's recommended that you use the JSONP proxy, or if you have control over the server side, then enable CORS.
To know more about CORS, please take a look at the following URLs:
- http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
The third property is reader
; this property is an object containing properties that will specify how the data will be handled (loaded) by Ext JS. It's important that we define a reader, otherwise the store won't be able to load the data properly.
So, at this point, we can load the data from our web server using Ajax. In order to test our code, let's create an HTML file importing the Ext
library, our model(s), and our store:
//Step 1 var store = Ext.create("Myapp.store.customers.Customers"); //Step 2 store.load(function(records, operation, success) { console.log('loaded records');//Step 3 Ext.each(records, function(record, index, records){ console.log( record.get("name") + ' - ' + record.data.contractInfo.contractId ); }); });
The steps are explained as follows:
- Step 1: We create the store as usual and save the reference in a variable.
- Step 2: We execute the
load
method. This method internally executes the read operation, makes the Ajax call to the server, and then loads the data into the store. The function that we give to theload
method as a parameter is a callback that will be executed after the records are loaded into the store. We are doing it in this way because Ajax is asynchronous, and we never know when the server is going to respond. - Step 3: The last step iterates through the records of the store and prints the name for each invoice in the JavaScript console.
Before we execute our example, we should create the serverside/customers.json
file. We're going to use JSON to encode the data, as follows:
{ "success":true, "id":"id", "records":[ { "id": 10001, "name": "Acme corp2", "phone": "+52-01-55-4444-3210", "website": "www.acmecorp.com", "status": "Active", "clientSince": "2010-01-01 14:35", "contractInfo":{ "id":444, "contractId":"ct-001-444", "documentType":"PDF" } },{ "id": 10002, "name": "Candy Store LTD", "phone": "+52-01-66-3333-3895", "website": "www.candyworld.com", "status": "Active", "clientSince": "2011-01-01 14:35", "contractInfo":{ "id":9998, "contractId":"ct-001-9998", "documentType":"DOCX" } } ] }
We have an object that contains an array of objects that hold our information; each object contains the same properties as that of our Customer
model, and also the relation one-to-one from the Contract
model.
Now, if we execute the test, we will see two records in the console. If we execute the count
method in our store, we will see that it only contains two elements.
Readers
Readers let Ext JS understand how to handle the response and fill the store with models containing the correct information.
As we saw in the previous example we used:
reader: { type:'json', rootProperty:'records' }
The type
property defines how our information is decoded. In this case, we are assigning the json
type to the property, but we can also use the xml
or array
type if needed.
The rootProperty
allows us to define the name of the property in the server response, where all objects containing the information for our models are located. This property should be an array in our JSON response. In this case, we set records
because our JSON response uses that name, but it could be anything. If we have nested objects, we can use a dot (.
) to go as deep as we need. For example, let's suppose we get the following response:
{ "success" :"true", "id":"id", "output":{ "appRecords":[{ our data .... }], "customerRecords":[{ our data .... }] } }
The previous response contains the array of information inside of an object output; we need to configure our reader, so it should be able to read this response correctly. We need to change the rootProperty
as follows:
reader: { type:'json', rootProperty:'output.customerRecords' }
We have only modified the rootProperty
using a dot to get one level deeper. We can go as deep as we need. It doesn't matter how many levels we have to go, but we need to make sure that we are setting this configuration correctly, pointing to the array of data where our models will be filled.
Let's test our code again (proxy_02.js
) by refreshing the browser. Now, we'll see the same output as before.
XML reader
The XML reader makes some relative changes to JSON, because in this case, we need to specify some other properties in the reader, to ensure the XML is well interpreted by Ext JS. Take a look at the following code:
proxy:{ type:'ajax', url: 'serverside/customers.xml', reader: { type: 'xml', rootProperty: 'data', record:'customer', totalProperty: 'total', successProperty: 'success' } }
We have only changed the url
property to our reader, so that it points to an XML file that contains our information, instead of the JSON file. The properties we are using are as follows:
- The
type
property was set toxml
. This way, our reader will be able to read the server response correctly. - The
rootProperty
defines the Element (node) in XML that Ext JS will check to look for records (sub nodes). - We also added
record
. This property allows us to define the tag where the information will be in the XML response; in this case, we usedcustomer
. - Finally, we added
totalProperty
andsuccessProperty
, which are nodes defining some values that the store will read for functionality.
Now, let's create the XML file that holds our information. This file should be called serverside/customers.xml,
and will contain the following code:
<?xml version="1.0" encoding="UTF-8"?> <data> <success>true</success> <total>2</total> <customer> <id>10001</id> <name>Acme corp2</name> <phone>+52-01-55-4444-3210</phone> <website>www.acmecorp.com</website> <status>Active</status> <clientSince>2010-01-01 14:35</clientSince> <contractInfo> <id>444</id> <contractId>ct-001-444</contractId> <documentType>PDF</documentType> </contractInfo> </customer> <customer> <id>10002</id> <name>Candy Store LTD</name> <phone>+52-01-66-3333-3895</phone> <website>www.candyworld.com</website> <status>Active</status> <clientSince>2011-01-01 14:35</clientSince> <contractInfo> <id>9998</id> <contractId>ct-001-9998</contractId> <documentType>DOCX</documentType> </contractInfo> </customer> </data>
First, we have defined the root node that contains the invoices information. This root node is called data
. If we change the name of this node, then we should also change the root
property in our reader to match this node.
Each customer
node contains the data for our models/records. We have defined a new record
property in our reader configuration to set the name of the node, where the information should be in our XML response.
Now, let's test our changes by refreshing our browser. If everything goes fine, we will see the same response as in the previous examples. Take a look at the next screenshot:
The result is exactly the same as when we used the JSON reader, however, if we go to the Network tab in the developers tools, we can see that in this case, the server is responding with XML.
By using readers, we can switch easily from using JSON or XML as our source of data. We don't have to change anything else in our code, but just configure each URL and reader correctly.