Perform CRUD Operations Using Sencha Touch MVC

In this article we will see how to perform some CRUD operations in Sencha Touch 2.

Before reading this article please goes through the following articles.

  1. Introduction to Sencha Touch 2
  2. Hello World App using Sencha Touch 2
  3. Sample form application using Sencha Touch 2
  4. Dealing with containers in Sencha Touch 2
  5. Working with DataBound Controls
  6. Introduction to MVC in Sencha Touch 2
  7. Create your first MVC application using Sencha Touch 2

Introduction

In the last article of this series we created our first MVC application using Sencha Touch 2 where we saw everything related to MVC. Now we have the knowledge of Sencha Touch’s Models, Controllers, Views, and Store so now we can proceed to perform some CRUD operations using Sencha Touch 2. So in this article we will see how to do those operations in Sencha Touch 2.

Here in Sencha Touch 2 we saw in our introduction article that Sencha Touch supports HTML5. Hence here we will use the local-storage feature of HTML5 to store and retrieve the data with the same. We will have a look at performing operations on the server as well. So let’s continue from our previous article where we created a nice Sencha Touch MVC application. In the last article we were pulling our data from the users.json file on the server here we will modify it a little bit to use HTML5 local-storage.

Modify the Store to use Local-Storage

Here we will just modify our existing store that communicates with the server to use local-storage of HTML5. So put the following lines in your UserStore.js file.

Ext.define("SenchaApp.store.UserStore", {
extend: 'Ext.data.Store',
storeId: "usersStore",
requires: ['Ext.data.proxy.LocalStorage'],
config: {
model: "SenchaApp.model.UserModel",
autoLoad: true,
autoSync:true,
proxy: {
type: 'localstorage',//uses html5 index db feature
id: 'SenchaApp_Users'//must be unique
}
/*proxy: {//server proxy
type: 'ajax',
header: {
"Content-Type": "application/json"
},
actionMethods: {//methods to perform individual task
read: 'GET',
create:'POST'
},
api: {//to perform set of actions
read: '/ServiceClass.svc/LoadUser',
create: '/ServiceClass.svc/AddUser',
destroy: '/ServiceClass.svc/Removeuser',
update: '/ServiceClass.svc/UpdateUser'
},
reader: {
type: 'json',
rootProperty: 'd'
}
}*/
}
});
 

In the above snippet you can see we just commented out the server proxy to use the local-storage proxy. We also added one required attribute to download the LocalStorage.js class of the framework. Here if you need to perform operations on the back-end server just uncomment the commented code and remove the local storage proxy. To perform a set of actions on the server end we must specify various URLs pointing to different methods under the API attribute. As in the previous demo we were using only a single URL property used when only loading data from the server and a simple URL will be the default for read operations.

Modify your Main.js

Now here our purpose is to add a user and store the user information in a HTML5 index db. So here we need to add one button that will open an empty form to enter user details. As in the last article we already created a UserDetailsView.js that contains all the fields to hold user information when the user clicks on a list item. So here we will use the same UserDetailView.js as a data entry form. Here now we need one button that will open a blank form so modify your Main.js as below.

Ext.define('SenchaApp.view.Main', {
extend: 'Ext.NavigationView',
xtype: 'main',
fullscreen: true,
config: {
id:'mainView',
items: [
{
xtype: 'userList',
title:'User List',
height:'100%',
}
], navigationBar: {
ui: 'dark',
docked: 'top',
items: [{
xtype: 'button',
itemId: 'AddNew',
text: 'Add New'
}]
},
}
});
 

Here in the preceding snippet we just added the navigation bar to our Main view with a button. You can add more buttons or other controls as you need. We will write this button logic in the last when we modify the controller class.

Modify UserDetailView.js

Since we now have a UserDetailView that contains fields, now we will add two more buttons to this view to do the Save and Delete actions. So modify your UserDetailView.js as in the following.

Ext.define('SenchaApp.view.UserDetailView', {
extend: 'Ext.form.Panel',
xtype: 'userDetail',
config: {
itemId: 'userDetail',
id:'userDetailView',
title: 'User Details',
fullscreen: true,
items: [
{
xtype: 'hiddenfield',
name:'id'
},
{
xtype: 'textfield',
name: 'Name',
label: 'Name'
},
{
xtype: 'textfield',
name: 'City',
label: 'City'
},
{
xtype: 'textfield',
name: 'Points',
label: 'Points'
}, {
xtype: 'toolbar',
dock: 'bottom',
items: [{
xtype: 'button',
itemId: 'Save',
text: 'Save',
ui: 'confirm'
}, {
xtype: 'button',
itemId: 'Delete',
text: 'Delete',
ui: 'decline'
}]
}
]
}
});

Here in the preceding snippet we see we have just added one toolbar and two buttons inside it. We will see those buttons in action in our next step.

Modify UserController.js

Now it’s time to actually write our logic to perform CRUD operations. As in the previous steps we added three buttons in two different views, in other words Main View and UserDetailView. Here now we will specify tap actions for those buttons and an actual implementation of the actions. So modify your UserController.js with the following snippets.

  Ext.define('SenchaApp.controller.UserController',

  {

      extend: 'Ext.app.Controller',

      views: ['SenchaApp.view.UserListView', 'SenchaApp.view.UserDetailView'],

      config: {

          control: {

              userList: {

                  //add event for the component

                  itemtap: 'onUserTap'

              },

              addNew: {

                  tap: 'onAddNew'

              },

              mainView: {

                  push: 'onPop'

              },

              saveBtn: {

                  tap: 'onSave'

              },

              deleteBtn: {

                  tap: 'onDelete'

              }

          },

          refs: {

              //this section automatically generates getter and setter method for the component

              userList: 'list[itemId=userList]', //getUserList() gives user list

              mainView: '#mainView', //getMainView() gives main view

              addNew: 'button[itemId=AddNew]',

              saveBtn: 'button[itemId=Save]',

              deleteBtn: 'button[itemId=Delete]'

          }

      },

      onUserTap: function (list, index, target, record, e, eOpts) {

          var me = this;

          var nav = me.getMainView(); //getter method

          //create model add data here we get the record from list's tap event. you can load store seperatly also

          var model = Ext.create('SenchaApp.model.UserModel', {

              id: record.data.id,

              Name: record.data.Name,

              City: record.data.City,

              Points: record.data.Points

          });

          //create new detail view

          var userdetailsView = Ext.create('SenchaApp.view.UserDetailView');

          //set created model with data to newly create view

          userdetailsView.setRecord(model);

          //push this new view to main view

          nav.push(userdetailsView);

          me.getAddNew().hide(true);

          me.getSaveBtn().show(true);

          me.getDeleteBtn().show(true);

      },

      onAddNew: function (btn, e, eOpts) {

          var me = this;

          var nav = me.getMainView();

          var userdetailsView = Ext.create('SenchaApp.view.UserDetailView');

          nav.push(userdetailsView);

      },

      onSave: function (btn, e, eOpts) {

          var me = this;

          var nav = me.getMainView();

          //get details view and get record

          var detailView = nav.down('formpanel[itemId=userDetail]');

          var record = detailView.getValues();

          var userStore = me.getUserList().getStore();

          var storeRec = userStore.findExact('id', record.id);

          if (storeRec > 0) {

              //if existing record then update

              userStore.findRecord('id', record.id).set('Name', record.Name);

              userStore.findRecord('id', record.id).set('City', record.City);

              userStore.findRecord('id', record.id).set('Points', record.Points);

          } else {

              //add record to store and sync it to persist change

              //if using server proxy

              //var operation = Ext.data.Operation({ action: 'create', records: record });

              // userStore.getProxy().create(operation);

              userStore.add(record);

              userStore.sync();

          }

          //after adding record go back to list

          nav.pop();

      },

      onDelete: function (btn, e, eOpts) {

          var me = this;

          var nav = me.getMainView();

          //get details view and get record

          var detailView = nav.down('formpanel[itemId=userDetail]');

          var record = detailView.getRecord();

 

          var userStore = me.getUserList().getStore();

          //add record to store and sync it to persist change

          userStore.remove(record);

          userStore.sync();

          //after adding record go back to list

          nav.pop();

      }

  });

</script> 

If you see in the above snippet we took a reference to three of the buttons, in other words Add New, Save and Delete respectively in our refs section and assigned a tap event to those buttons with individual methods. So let’s see each action independently so you will get a clear idea.

Add New

So in the above snippet we have an onAddNew function that will be be fired on an Add New button click. Here our purpose is to open a blank form to get the details from the user. So here first we are getting a reference to our main view then we are creating a new empty view and add it to the main view by using the push method. Here our main view is of the type NavigationView of the framework that is able to store references of previous views also and to retrieve the previous view we can just call the pop method of the main view.

Here we have two different views, one for a list and one for details. So initially we have loaded the list in the main view and on the clicking of a list item or on a click of an add new we are adding a detail view. So here once the view is added to the main view we need not create the same view again and again, we just use push and pop methods. For example, if we are on the details view and after performing save or delete operations we need to navigate the user back to the list view then we need not create the list view again and push it to the main view. This list view already exists in the main view and we simply need to pop it back.

Save

To do a save operation we have the onSave function that first gets the reference to our main view and on the basis of the main view it gets a reference to the detail view. Since we already know that whenever we need to do operations then the Store is our friend to do that hence we get the Store object from our list view. Next here we are performing a check of finding a record in the Store. First if the record is available then we will update it. If the record does not exist in the Store then we will add it. This facility is available only because we are using the local-storage proxy. If you have a server proxy then you must handle this on the server.

Here for local-storage we are simply adding the new record to the Store and sync it to persist the changes. If you are using a server proxy then by simply adding a record it will be not be done. For that you need to create an operation object that can be created using the Ext.data.Operation class. I already commented on the code in the snippet above. This operation contains various options like what action we need to fire to pick a specific URL and hit it. For example, if we need to add a new record then we need to specify an action as "create" that will pick a new URL from the Store API and preform further actions. If you need to send some data to the server then you can send a user params attribute in the operation.

And finally we are returning our user to list the page to verify or not the record was added using the pop method of our main view as we explained in the last step.

Delete

To delete the record we created the onDelete function. When delete buttons are hit then this function will be fired. Here what we are doing is simply getting the record opened in detail view and removing it from the Store. This same thing is available because of the local-storage proxy. If it is a server proxy then we need to create the same operation with the delete action. And finally we are returning the user to the list page with the pop method of the main view.

List Page

List

Detail Page

Delete

Conclusion

In this easy way we can do CRUD operations in Sencha Touch 2. Here again one more benefit is that we have strong support for using the HTML5 index db feature if we need to store some offline data. In the next article we will see types of store proxies so stay tuned.