ExtJS and Spring MVC Framework: CRUD DataGrid Example
Posted on : 22-03-2010 | By : Loiane | In : ExtJS, Grid
35
This tutorial will walk through how to implement a CRUD (Create, Read, Update, Delete) DataGrid using ExtJS and Spring Framework.
What do we usually want to do with data?
- Create (Insert)
- Read / Retrieve (Select)
- Update (Update)
- Delete / Destroy (Delete)
Until ExtJS 3.0 we only could READ data using a dataGrid. If you wanted to update, insert or delete, you had to do some code to make these actions work. Now ExtJS 3.0 (and newest versions) introduces the ext.data.writer, and you do not need all that work to have a CRUD Grid.
So… What do I need to add in my code to make all these things working together?
In this example, I’m going to use JSON as data format exchange between the browser and the server.
First, you need an Ext.data.JsonWriter:
// The new DataWriter component.
var writer = new Ext.data.JsonWriter({
encode: true,
writeAllFields: false
});
Where writeAllFields identifies that we want to write all the fields from the record to the database. If you have a fancy ORM then maybe you can set this to false. For example. This is my record type declaration:
var Contact = Ext.data.Record.create([
{name: 'id'},
{
name: 'name',
type: 'string'
}, {
name: 'phone',
type: 'string'
}, {
name: 'email',
type: 'string'
}, {
name: 'birthday',
type: 'date',
dateFormat: 'm/d/Y'
}]);
If I only update the name of any contact in the datagrid, the app will only send the contact id and contact name back to server. In another words, the app will only send the updated data to the server + id (in update cases) and only the contact id in delete cases. Try to change it to true and enable Firebug plugin in your browser to see what happens. Now you need to setup a proxy like this one:
var proxy = new Ext.data.HttpProxy({
api: {
read : 'contact/view.action',
create : 'contact/create.action',
update: 'contact/update.action',
destroy: 'contact/delete.action'
}
});
FYI, this is how my reader looks like:
var reader = new Ext.data.JsonReader({
totalProperty: 'total',
successProperty: 'success',
idProperty: 'id',
root: 'data',
messageProperty: 'message' // <-- New "messageProperty" meta-data
},
Contact);
The Writer and the proxy (and the reader) can be hooked to the store like this:
// Typical Store collecting the Proxy, Reader and Writer together.
var store = new Ext.data.Store({
id: 'user',
proxy: proxy,
reader: reader,
writer: writer, // <-- plug a DataWriter into the store just as you would a Reader
autoSave: false // <-- false would delay executing create, update, destroy requests until specifically told to do so with some [save] buton.
});
Where autosave identifies if you want the data in automatically saving mode (you do not need a save button, the app will send the actions automatically to the server). In this case, I implemented a save button, so every record with new or updated value will have a red mark on the cell left up corner). When the user alters a value in the grid, then a “save” event occurs (if autosave is true). Upon the “save” event the grid determines which cells has been altered. When we have an altered cell, then the corresponding record is sent to the server with the ‘root’ from the reader around it. E.g if we read with root “data”, then we send back with root “data”. We can have several records being sent at once. When updating to the server (e.g multiple edits). And to make you life even easier, let’s use the RowEditor plugin, so you can easily edit or add new records. All you have to do is to add the css and js files in your page:
<!-- Row Editor plugin css --> <link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/ux/css/rowEditorCustom.css" /> <link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/shared/examples.css" /> <link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/ux/css/RowEditor.css" /> <!-- Row Editor plugin js --> <script src="/extjs-crud-grid/ext-3.1.1/examples/ux/RowEditor.js"></script>
Add the plugin on you grid declaration:
var editor = new Ext.ux.grid.RowEditor({
saveText: 'Update'
});
// create grid
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header: "NAME",
width: 170,
sortable: true,
dataIndex: 'name',
editor: {
xtype: 'textfield',
allowBlank: false
}},
{header: "PHONE #",
width: 150,
sortable: true,
dataIndex: 'phone',
editor: {
xtype: 'textfield',
allowBlank: false
}},
{header: "EMAIL",
width: 150,
sortable: true,
dataIndex: 'email',
editor: {
xtype: 'textfield',
allowBlank: false
}},
{header: "BIRTHDAY",
width: 100,
sortable: true,
dataIndex: 'birthday',
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
editor: new Ext.form.DateField ({
allowBlank: false,
format: 'm/d/Y',
maxValue: (new Date())
})}
],
plugins: [editor],
title: 'My Contacts',
height: 300,
width:610,
frame:true,
tbar: [{
iconCls: 'icon-user-add',
text: 'Add Contact',
handler: function(){
var e = new Contact({
name: 'New Guy',
phone: '(000) 000-0000',
email: 'new@loianetest.com',
birthday: '01/01/2000'
});
editor.stopEditing();
store.insert(0, e);
grid.getView().refresh();
grid.getSelectionModel().selectRow(0);
editor.startEditing(0);
}
},{
iconCls: 'icon-user-delete',
text: 'Remove Contact',
handler: function(){
editor.stopEditing();
var s = grid.getSelectionModel().getSelections();
for(var i = 0, r; r = s[i]; i++){
store.remove(r);
}
}
},{
iconCls: 'icon-user-save',
text: 'Save All Modifications',
handler: function(){
store.save();
}
}]
});
Finally, you need some server side code. This is how my Controller looks like:
package com.loiane.web;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.loiane.model.Contact;
import com.loiane.service.ContactService;
public class ContactController extends MultiActionController {
private ContactService contactService;
public ModelAndView view(HttpServletRequest request,
HttpServletResponse response) throws Exception {
try{
List<Contact> contacts = contactService.getContactList();
return getModelMap(contacts);
} catch (Exception e) {
return getModelMapError("Error trying to retrieve contacts.");
}
}
public ModelAndView create(HttpServletRequest request,
HttpServletResponse response) throws Exception {
try{
Object data = request.getParameter("data");
List<Contact> contacts = contactService.create(data);
return getModelMap(contacts);
} catch (Exception e) {
return getModelMapError("Error trying to create contact.");
}
}
public ModelAndView update(HttpServletRequest request,
HttpServletResponse response) throws Exception {
try{
Object data = request.getParameter("data");
List<Contact> contacts = contactService.update(data);
return getModelMap(contacts);
} catch (Exception e) {
return getModelMapError("Error trying to update contact.");
}
}
public ModelAndView delete(HttpServletRequest request,
HttpServletResponse response) throws Exception {
try{
String data = request.getParameter("data");
contactService.delete(data);
Map<String,Object> modelMap = new HashMap<String,Object>(3);
modelMap.put("success", true);
return new ModelAndView("jsonView", modelMap);
} catch (Exception e) {
return getModelMapError("Error trying to delete contact.");
}
}
/**
* Generates modelMap to return in the modelAndView
* @param contacts
* @return
*/
private ModelAndView getModelMap(List<Contact> contacts){
Map<String,Object> modelMap = new HashMap<String,Object>(3);
modelMap.put("total", contacts.size());
modelMap.put("data", contacts);
modelMap.put("success", true);
return new ModelAndView("jsonView", modelMap);
}
/**
* Generates modelMap to return in the modelAndView in case
* of exception
* @param msg message
* @return
*/
private ModelAndView getModelMapError(String msg){
Map<String,Object> modelMap = new HashMap<String,Object>(2);
modelMap.put("message", msg);
modelMap.put("success", false);
return new ModelAndView("jsonView",modelMap);
}
/**
* Spring use - DI
* @param dadoService
*/
public void setContactService(ContactService contactService) {
this.contactService = contactService;
}
}
If you want to see all the code (complete project will all the necessary files to run this app), download it from my GitHub repository: http://github.com/loiane/extjs-crud-grid
I just want to make one more observation: You can also use dataWriter to save the data dragged from an excel file and dropped into the grid (remember DataDrop plugin?). I also included this plugin in this code project (check out my Github repository).
Happy coding!
Updated: I posted a new CRUD DataGrid example, using Spring MVC 3 and Hibernate 3.5: http://loianegroner.com/2010/09/extjs-spring-mvc-3-and-hibernate-3-5-crud-datagrid-example/




Very nice example on how to use Ext JS and Spring. Thanks for sharing your thoughts so elegantly. Really enjoyed reading about the CRUD support implementation. Hope to read more soon.
Social comments and analytics for this post…
This post was mentioned on Twitter by loiane: Blog Post: ExtJS and Spring MVC Framework: CRUD DataGrid Example http://bit.ly/aSInjc...
that’s awesome ! great work
thanks
Thanks for good article ! It’s the first site with source code for Java – ExtJS pair that I found on Inet .
muy limpio el ejemplo, que me sirvio de base para hacer un ejemplo propio que en breve estaré por subir al github. thank you so much!!!!
@bein
Gracias!
Thanks!
Thanks for good article !
!!! )
please if you have same example but with data base communication i am beginer with JSP can you send me exemple (iam sorry for bad english
Like Hakim, I’m wating for a example with DB because I’m confused with the fake Database with Collection,,,
And like hakim,,,sorry for my english,,,
do you understand spanish?
@Jeison
I’m writing a full example with DB.
And yes, I do understand a little bit of Spanish. If it is more confortable for you, you can write in Spanish!
Espero mientras que el ejemplo con una base de datos que será grande!
thank you for your answer
I try to write in Spanish
Hello Loiane,
Thanks for the great example for CRUD based grid. I am working on a similar project , But I am struck because row editor is not firing write event after the store.save. Did you encounter similar problems, if so what was your solution to resolve it.
Appreciate your help on this.
Again great work.
Thanks
Manju
Sir
i want to use remove and add button, for effected on database plz send me add and remove button code which is change(add/remove )data from database………
Chandan Kumar: The code to remove the record from database it’s already implemented at this post.
the change that you have to implement is on java code. But that code is source to another post.
hello
@jeisonyou have a full example with DB.I’m stuck please help
yes, I have adapted this example to work with a database, but I have no blog, I could some code to send your email.
in fact the only change from this post is in the DAO, the rest is equal.
Hello Jeison,
here is my email hakim.arbi@gmail.com.
thank you very much for your reply
I wait patiently for your email
You are awesome!
It’s a great job
Like Hakim and Jeison, I’m wating for an example with DB.
If some body have an example with DB, plz send it to me at : errih21@hotmail.fr
Thank you
Excellent!
@ Loiane I’m wating for an example with DB
Thanks Loiane, for this very well articulated example of the Extjs row-editor. I am anewbee with Spring and I tried to follow what you did,the part I need help to understand is the following;
var proxy = new Ext.data.HttpProxy({
api: {
read : ‘contact/view.action’,
create : ‘contact/create.action’,
update: ‘contact/update.action’,
destroy: ‘contact/delete.action’
}
});
Where are these params being called in this function found?
Thanks in anticipation.
jbb
Hi, I have a problem with this error: “Exception thrown and not collected” / “Excepción lanzada y no recogida”, I check my code but I can’t find the solution. any idea?
Thank you for taking the time to post this work.
It has been very helpful.
Q: Where can I hook into the success callback to call clean up functions?
Thanks
Hi Loaine,
Obrigado tanto para o excelente tutorial. Por favor, mantenha o bom trabalho!!
Taguchi
Hello Jeison,
I understand you have successfully adapted this example with a database, like Hakim am stack with the fake database. Could you please help here.
thanks
Jessb
thanks man !!!!!!!!!!!!!!!!!
Hi Jessb I want to see how the db version of this example work …I will really appreciate if you can send me the db version of this example at paul.laskar@gmail.com
Thanks
Hi Paul,
Sorry for delaying the response, I have not been around. I will contact you at your email with what I have.
Jssb
great tutorial, it also helped me out. Not to hijack the post, but if you’d like to see other examples and tutorials on extjs, I have them on my site. Thanks again for sharing.
Hi ,
I tried run the above programe and i am getting error. In internet explorer it is showing error in rowEditor.js file
for(var i = 0, len = cm.getColumnCount(); i < len; i++){
var c = cm.getColumnAt(i),
ed = c.getEditor();
if(!ed){
ed = c.displayEditor || new Ext.form.DisplayField();
}else{
ed = ed.field;
}
ed = ed.field;—- filed is undefined.
Can somebody help me in resolving
[...] was a requested post. I’ve got a lot of comments from my previous CRUD Grid example and some emails. I made some adjustments to current code, but the idea is still the same. I hope I [...]
[...] post foi um pedido de alguns leitores do post anterior de CRUD Grid (e do blog em inglês), além de ter recebido alguns emails. Fiz alguns ajustes em relação ao post anterior, mas a [...]
Hey Guys,
Just posted an example with DB: http://loianegroner.com/2010/09/extjs-spring-mvc-3-and-hibernate-3-5-crud-datagrid-example/
Hi Loiane,
You’ve definitely become a very talented EXT JS coder. Thanks for sharing your knowledge and allowing us newbies to “learn” ext js with you.
Por favor, mantenha o bom trabalho!!
Taguchi