Perform CRUD Operations Using Sencha Touch MVC

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 where 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.
  1. Ext.define("SenchaApp.store.UserStore", {  
  2. extend: 'Ext.data.Store',  
  3. storeId: "usersStore",  
  4. requires: ['Ext.data.proxy.LocalStorage'],  
  5. config: {  
  6. model: "SenchaApp.model.UserModel",  
  7. autoLoad: true,  
  8. autoSync:true,  
  9. proxy: {  
  10. type: 'localstorage',//uses html5 index db feature  
  11. id: 'SenchaApp_Users'//must be unique  
  12. }  
  13. /*proxy: {//server proxy 
  14. type: 'ajax', 
  15. header: { 
  16. "Content-Type": "application/json" 
  17. }, 
  18. actionMethods: {//methods to perform individual task 
  19. read: 'GET', 
  20. create:'POST' 
  21. }, 
  22. api: {//to perform set of actions 
  23. read: '/ServiceClass.svc/LoadUser', 
  24. create: '/ServiceClass.svc/AddUser', 
  25. destroy: '/ServiceClass.svc/Removeuser', 
  26. update: '/ServiceClass.svc/UpdateUser' 
  27. }, 
  28. reader: { 
  29. type: 'json', 
  30. rootProperty: 'd' 
  31. } 
  32. }*/  
  33. }  
  34. });  
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 reading operations.
 
Modify your Main.js
 
Now here our purpose is to add a user and store the user information in an 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.
  1. Ext.define('SenchaApp.view.Main', {  
  2. extend: 'Ext.NavigationView',  
  3. xtype: 'main',  
  4. fullscreen: true,  
  5. config: {  
  6. id:'mainView',  
  7. items: [  
  8. {  
  9. xtype: 'userList',  
  10. title:'User List',  
  11. height:'100%',  
  12. }  
  13. ], navigationBar: {  
  14. ui: 'dark',  
  15. docked: 'top',  
  16. items: [{  
  17. xtype: 'button',  
  18. itemId: 'AddNew',  
  19. text: 'Add New'  
  20. }]  
  21. },  
  22. }  
  23. });  
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.
  1. Ext.define('SenchaApp.view.UserDetailView', {  
  2. extend: 'Ext.form.Panel',  
  3. xtype: 'userDetail',  
  4. config: {  
  5. itemId: 'userDetail',  
  6. id:'userDetailView',  
  7. title: 'User Details',  
  8. fullscreen: true,  
  9. items: [  
  10. {  
  11. xtype: 'hiddenfield',  
  12. name:'id'  
  13. },  
  14. {  
  15. xtype: 'textfield',  
  16. name: 'Name',  
  17. label: 'Name'  
  18. },  
  19. {  
  20. xtype: 'textfield',  
  21. name: 'City',  
  22. label: 'City'  
  23. },  
  24. {  
  25. xtype: 'textfield',  
  26. name: 'Points',  
  27. label: 'Points'  
  28. }, {  
  29. xtype: 'toolbar',  
  30. dock: 'bottom',  
  31. items: [{  
  32. xtype: 'button',  
  33. itemId: 'Save',  
  34. text: 'Save',  
  35. ui: 'confirm'  
  36. }, {  
  37. xtype: 'button',  
  38. itemId: 'Delete',  
  39. text: 'Delete',  
  40. ui: 'decline'  
  41. }]  
  42. }  
  43. ]  
  44. }  
  45. }); 
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 actual implementation of the actions. So modify your UserController.js with the following snippets.
  1. Ext.define('SenchaApp.controller.UserController',  
  2.   {  
  3.       extend: 'Ext.app.Controller',  
  4.       views: ['SenchaApp.view.UserListView''SenchaApp.view.UserDetailView'],  
  5.       config: {  
  6.           control: {  
  7.               userList: {  
  8.                   //add event for the component  
  9.                   itemtap: 'onUserTap'  
  10.               },  
  11.               addNew: {  
  12.                   tap: 'onAddNew'  
  13.               },  
  14.               mainView: {  
  15.                   push: 'onPop'  
  16.               },  
  17.               saveBtn: {  
  18.                   tap: 'onSave'  
  19.               },  
  20.               deleteBtn: {  
  21.                   tap: 'onDelete'  
  22.               }  
  23.           },  
  24.           refs: {  
  25.               //this section automatically generates getter and setter method for the component  
  26.               userList: 'list[itemId=userList]'//getUserList() gives user list  
  27.               mainView: '#mainView'//getMainView() gives main view  
  28.               addNew: 'button[itemId=AddNew]',  
  29.               saveBtn: 'button[itemId=Save]',  
  30.               deleteBtn: 'button[itemId=Delete]'  
  31.           }  
  32.       },  
  33.       onUserTap: function (list, index, target, record, e, eOpts) {  
  34.           var me = this;  
  35.           var nav = me.getMainView(); //getter method  
  36.           //create model add data here we get the record from list's tap event. you can load store seperatly also  
  37.           var model = Ext.create('SenchaApp.model.UserModel', {  
  38.               id: record.data.id,  
  39.               Name: record.data.Name,  
  40.               City: record.data.City,  
  41.               Points: record.data.Points  
  42.           });  
  43.           //create new detail view  
  44.           var userdetailsView = Ext.create('SenchaApp.view.UserDetailView');  
  45.           //set created model with data to newly create view  
  46.           userdetailsView.setRecord(model);  
  47.           //push this new view to main view  
  48.           nav.push(userdetailsView);  
  49.           me.getAddNew().hide(true);  
  50.           me.getSaveBtn().show(true);  
  51.           me.getDeleteBtn().show(true);  
  52.       },  
  53.       onAddNew: function (btn, e, eOpts) {  
  54.           var me = this;  
  55.           var nav = me.getMainView();  
  56.           var userdetailsView = Ext.create('SenchaApp.view.UserDetailView');  
  57.           nav.push(userdetailsView);  
  58.       },  
  59.       onSave: function (btn, e, eOpts) {  
  60.           var me = this;  
  61.           var nav = me.getMainView();  
  62.           //get details view and get record  
  63.           var detailView = nav.down('formpanel[itemId=userDetail]');  
  64.           var record = detailView.getValues();  
  65.           var userStore = me.getUserList().getStore();  
  66.           var storeRec = userStore.findExact('id', record.id);  
  67.           if (storeRec > 0) {  
  68.               //if existing record then update  
  69.               userStore.findRecord('id', record.id).set('Name', record.Name);  
  70.               userStore.findRecord('id', record.id).set('City', record.City);  
  71.               userStore.findRecord('id', record.id).set('Points', record.Points);  
  72.           } else {  
  73.               //add record to store and sync it to persist change  
  74.               //if using server proxy  
  75.               //var operation = Ext.data.Operation({ action: 'create', records: record });  
  76.               // userStore.getProxy().create(operation);  
  77.               userStore.add(record);  
  78.               userStore.sync();  
  79.           }  
  80.           //after adding record go back to list  
  81.           nav.pop();  
  82.       },  
  83.       onDelete: function (btn, e, eOpts) {  
  84.           var me = this;  
  85.           var nav = me.getMainView();  
  86.           //get details view and get record  
  87.           var detailView = nav.down('formpanel[itemId=userDetail]');  
  88.           var record = detailView.getRecord();  
  89.    
  90.           var userStore = me.getUserList().getStore();  
  91.           //add record to store and sync it to persist change  
  92.           userStore.remove(record);  
  93.           userStore.sync();  
  94.           //after adding record go back to list  
  95.           nav.pop();  
  96.       }  
  97.   });  
  98. </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 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 additional new we are adding a detailed 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 to 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.