Sencha Touch models have the ability to work with a proxy. This feature allows you to save and retrieve model data from the server, memory or local storage, without depending on a Sencha Touch data store.
The model methods you will learn in this article are the following:
- save
- erase
Let’s try them with a very simple scenario where the server side is a .NET handler written in C#. In this example you will create a simple Sencha Touch application with the following files:

In the model/Hotel.js file, you will define the Hotel model like so:
Ext.define('App.model.Hotel', {
extend: 'Ext.data.Model',
config: {
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' },
{ name: 'address', type: 'string' },
{ name: 'status', type: 'int' }
],
proxy: {
type: 'ajax',
api: {
create: '../../services/hotels.ashx?act=createhotel',
read: '../../services/hotels.ashx?act=loadhotel',
update: '../../services/hotels.ashx?act=updatehotel',
destroy: '../../services/hotels.ashx?act=erasehotel'
},
reader: {
rootProperty:'hotels'
}
}
}
});
Then, you need to create the hotels.ashx handler, which will be the server-side handler for the model’s proxy. For this example we will use C# as the server-side language. You can check out the PHP example if you prefer PHP.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using Newtonsoft.Json;
namespace st2tuts.Services
{
public class Hotels : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string hotelJson;
Hotel hotel;
string result = "{'success':false}";
string action = context.Request.QueryString["act"];
if (action != null)
{
switch (action.ToLower())
{
case "loadhotel":
string hotelId = context.Request.QueryString["id"];
// Here you would retrieve the hotel from the database...
// Returning a hard-coded hotel for demo purposes.
result = @"{'success':true,'hotels':[{'id': 1, 'name': 'Siesta by the Ocean', 'address': '1 Ocean Front, Happy Island', 'status': 1}]}";
break;
case "createhotel":
hotelJson = GetRequestPayload(context);
hotel = JsonConvert.DeserializeObject(hotelJson, typeof(Hotel)) as Hotel;
// Here you would save the hotel to the database...
// Returning success for demo purposes.
result = @"{'success':true,'hotels':[" + JsonConvert.SerializeObject(hotel) + "]}";
break;
case "updatehotel":
hotelJson = GetRequestPayload(context);
hotel = JsonConvert.DeserializeObject(hotelJson, typeof(Hotel)) as Hotel;
// Here you would save the hotel to the database...
// Returning success for demo purposes.
result = @"{'success':true,'hotels':[" + JsonConvert.SerializeObject(hotel) + "]}";
break;
case "erasehotel":
hotelJson = GetRequestPayload(context);
hotel = JsonConvert.DeserializeObject(hotelJson, typeof(Hotel)) as Hotel;
// Here you would delete the hotel from the database...
// Returning success for demo purposes.
result = @"{'success':true}";
break;
}
}
context.Response.ContentType = "application/json";
context.Response.Write(result);
}
private string GetRequestPayload(HttpContext context)
{
StreamReader r = new StreamReader(context.Request.InputStream);
context.Request.InputStream.Position = 0;
return r.ReadToEnd();
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
The Hotel class will look like this:
namespace st2tuts.Services
{
public class Hotel
{
public string id { get; set; }
public string name { get; set; }
public string address { get; set; }
public int status { get; set; }
}
}
Once the handler is ready, you can try the proxy by placing the following code in the app.js file:
Ext.application({
name: 'App',
requires: ['Ext.util.DelayedTask'],
models: ['App.model.Hotel'],
launch: function () {
App.model.Hotel.load(1, {
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
var hotel = Ext.create('App.model.Hotel', {
name: 'La Playa',
address: '100 Ocean Front, Happy Island',
status: 1
});
hotel.save({
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
var updateTask = Ext.create('Ext.util.DelayedTask', function () {
// Saving inside a delayed task, just to wait for the previous operations
// to execute on the server and invoke the callbacks.
hotel.set('name', 'Playa Hermosa');
hotel.save({
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
}, this);
updateTask.delay(3000);
var deleteTask = Ext.create('Ext.util.DelayedTask', function () {
// Erasing inside a delayed task, just to wait for the previous operations
// to execute on the server and invoke the callbacks.
hotel.erase({
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
}, this);
deleteTask.delay(6000);
},
proxySuccess: function (record, operation) {
switch (operation.getAction()) {
case 'create':
console.log('From the server: Created the ' + record.get('name') + ' hotel.');
break;
case 'read':
console.log('From the server: Loaded the ' + record.get('name') + ' hotel.');
break;
case 'update':
console.log('From the server: Updated the ' + record.get('name') + ' hotel.');
break;
case 'destroy':
console.log('From the server: Erased the ' + record.get('name') + ' hotel.');
break;
}
},
proxyFailure: function (record, operation) {
switch (operation.getAction()) {
case 'create':
console.log('From the server: Failed to create hotel.');
break;
case 'read':
console.log('From the server: Failed to read hotel.');
break;
case 'update':
console.log('From the server: Failed to update hotel.');
break;
case 'destroy':
console.log('From the server: Failed to erase hotel.');
break;
}
},
proxyCallback: function (record, operation) {
console.log('This function is always invoked, regardless of success or failure');
}
});
In Google Chrome, when you open the index.html, you will see the following output in the JavaScript console:

How It Works
You connect the Hotel model to a proxy through the model’s proxy config:
proxy: {
type: 'ajax',
api: {
create: '../../services/hotels.ashx?act=createhotel',
read: '../../services/hotels.ashx?act=loadhotel',
update: '../../services/hotels.ashx?act=updatehotel',
destroy: '../../services/hotels.ashx?act=erasehotel'
},
reader: {
rootProperty:'hotels'
}
}
The proxy we are using is of type ajax. Its api config allows you to specify which server-side end points will handle the create, read, update and destroy (CRUD) operations that can occur on the data.
The rootProperty config of the proxy’s reader defines which property of the JSON-encoded server response contains the data for the model.
On the server side, the Hotels.ashx handler’s ProcessRequest method inspects that act (short for action) query string parameter, defined in the proxy’s api config, to determine what operation will be performed.
Instead of executing database access code, for this example the handler will return canned responses that demonstrate the results of each operation:
if (action != null)
{
switch (action.ToLower())
{
case "loadhotel":
string hotelId = context.Request.QueryString["id"];
// Here you would retrieve the hotel from the database...
// Returning a hard-coded hotel for demo purposes.
result = @"{'success':true,'hotels':[{'id': 1, 'name': 'Siesta by the Ocean', 'address': '1 Ocean Front, Happy Island', 'status': 1}]}";
break;
case "createhotel":
hotelJson = GetRequestPayload(context);
hotel = JsonConvert.DeserializeObject(hotelJson, typeof(Hotel)) as Hotel;
// Here you would save the hotel to the database...
// Returning success for demo purposes.
result = @"{'success':true,'hotels':[" + JsonConvert.SerializeObject(hotel) + "]}";
break;
case "updatehotel":
hotelJson = GetRequestPayload(context);
hotel = JsonConvert.DeserializeObject(hotelJson, typeof(Hotel)) as Hotel;
// Here you would save the hotel to the database...
// Returning success for demo purposes.
result = @"{'success':true,'hotels':[" + JsonConvert.SerializeObject(hotel) + "]}";
break;
case "erasehotel":
hotelJson = GetRequestPayload(context);
hotel = JsonConvert.DeserializeObject(hotelJson, typeof(Hotel)) as Hotel;
// Here you would delete the hotel from the database...
// Returning success for demo purposes.
result = @"{'success':true}";
break;
}
}
context.Response.ContentType = "application/json";
context.Response.Write(result);
Switching back to the client-side, in the app.js file you will place code that executes each of the CRUD operations. First, a read:
App.model.Hotel.load(1, {
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
Second, a create:
var hotel = Ext.create('App.model.Hotel', {
name: 'La Playa',
address: '100 Ocean Front, Happy Island',
status: 1
});
hotel.save({
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
Third, an update:
var updateTask = Ext.create('Ext.util.DelayedTask', function () {
// Saving inside a delayed task, just to wait for the previous operations
// to execute on the server and invoke the callbacks.
hotel.set('name', 'Playa Hermosa');
hotel.save({
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
}, this);
updateTask.delay(3000);
And fourth, an erase:
var deleteTask = Ext.create('Ext.util.DelayedTask', function () {
// Erasing inside a delayed task, just to wait for the previous operations
// to execute on the server and invoke the callbacks.
hotel.erase({
scope: this,
success: this.proxySuccess,
failure: this.proxyFailure,
callback: this.proxyCallback
});
}, this);
deleteTask.delay(6000);
As the CRUD executes asynchronously, we are placing some of the operations inside a DelayedTask instance so we give the prior operation time to complete on the server. This is fine for demo purposes, but in your applications you don’t have to do this.
You can pass callback functions to the the load, save and erase methods of the model. In the example, you use the proxySuccess, proxyFailure and proxyCallback methods defined inside of the application function.
You can use the record and operation arguments of these callbacks to take action based on the results returned by the server:
proxySuccess: function (record, operation) {
switch (operation.getAction()) {
case 'create':
console.log('From the server: Created the ' + record.get('name') + ' hotel.');
break;
case 'read':
console.log('From the server: Loaded the ' + record.get('name') + ' hotel.');
break;
case 'update':
console.log('From the server: Updated the ' + record.get('name') + ' hotel.');
break;
case 'destroy':
console.log('From the server: Erased the ' + record.get('name') + ' hotel.');
break;
}
},
Want To Learn More?
My Sencha Touch books will teach you how to create a Sencha Touch application, step by step, from mockups to production build.


Hi Jorge, i read your article it is really a good one for beginners which i found on internet. I have implemented on my machine, working perfectly. I have just started working on app development and could not implement code on Create, Read, Update, Delete buttons in app.view.home. Code executes on launch: function() but when i try to implement on button click failed to do it. Kindly help me how can i implement CRUD on button clicks
Thanks
Hi Jorge,
Sorry to disturb you again, one more thing when i uploaded server side code on live server then i got the error “Access-Control-Allow-Origin” Could not access file.
Kindly help me to resolve this error.
Regards
Looks like you are calling a page on a different domain: https://developer.mozilla.org/en-US/docs/HTTP_access_control