| Summary: This article will walk you through using the grid, form and dialog in Ext to achieve list, create, update, delete, search and paging functions |
| Author: Fenqiang Zhuang |
| Published: June 16, 2007 |
| Ext Version: 1.1 |
Languages: English
|
In web applications, most of the pages can be cataloged as: List, Create, Read, Update, Delete. The Ext documentation center provides a good example for an inline editing grid. However, in many cases, an inline editing grid is not enough and a pop-up dialog is needed to achieve different kinds of fields in our form. Below is one of my simple examples to show you how to create/update a dialog form based on a user action in the grid. Download Source - for Ext 1.1 version
Demo updated with Ext 2.0 (www.feyasoft.com) -> click "Grid form dialog demo" icon on desktop
Source Code for Ext 2.0 -> click "Feyasoft source code" icon on desktop (navigate to javascript->feyasoft->demouser folder)
Contents |
List functionThis is the list accounts page, it includes paging, search/filter function, add and delete function.
Add filter/search drop-down menu in the Grid head panel.
/************************************************************ * create header panel * add filter field - search function ************************************************************/ var gridHead = grid.getView().getHeaderPanel(true); var tb = new Ext.Toolbar(gridHead); filterButton = new Ext.Toolbar.MenuButton({ icon: 'public/image/list-items.gif', cls: 'x-btn-text-icon', text: 'Choose Filter', tooltip: 'Select one of filter', menu: {items: [ new Ext.menu.CheckItem({ text: 'First Name', value: 'firstname', checked: true, group: 'filter',checkHandler:onItemCheck }), new Ext.menu.CheckItem({ text: 'Last Name', value: 'lastname', checked: false, group: 'filter', checkHandler: onItemCheck }), new Ext.menu.CheckItem({ text: 'Username', value: 'username', checked: false, group: 'filter', checkHandler: onItemCheck }) ]}, minWidth: 105 }); tb.add(filterButton); // Create the filter field var filter = Ext.get(tb.addDom({ // add a DomHelper config to the toolbar and return a reference to it tag: 'input', type: 'text', size: '30', value: '', style: 'background: #F0F0F9;' }).el); // press enter keyboard filter.on('keypress', function(e) { // setup an onkeypress event handler if(e.getKey() == e.ENTER && this.getValue().length > 0) {// listen for the ENTER key ds.load({params:{start:0, limit:myPageSize}}); } });
Add paging, add and delete button in the Grid footer panel.
/************************************************************ * create footer panel * actions and paging ************************************************************/ var gridFoot = grid.getView().getFooterPanel(true); // add a paging toolbar to the grid's footer var paging = new Ext.PagingToolbar(gridFoot, ds, { pageSize: myPageSize, displayInfo: true, displayMsg: 'total {2} results found. Current shows {0} - {1}', emptyMsg: "not result to display" }); // add the detailed add button paging.add('-', { pressed: true, enableToggle:true, text: 'Add', cls: '', toggleHandler: doAdd }); // add the detailed delete button paging.add('-', { pressed: true, enableToggle:true, text: 'Delete', cls: '', toggleHandler: doDel });
On paging function, you need send filterTxt and value to server before loading data.
/************************************************************ * load parameter to backend * have beforelaod function ************************************************************/ ds.on('beforeload', function() { ds.baseParams = { // modify the baseParams setting for this request filterValue: filter.getValue(),// retrieve the value of the filter input and assign it to a property named filter filterTxt: filterButton.getText() }; }); // trigger the data store load ds.load({params:{start:0, limit:myPageSize}});
List result get JSON data from server-side:
({"totalCount":52,"results":[{"lastname":"Zhuang","password":"12","firstname":"Fenqiang" ,"enterDate":"Jun 18, 2007","username":"ffzhuang","id":40},{"lastname":"gh","password":"gh","firstname":"gh-last","enterDate":"Jun 18, 2007","username":"gh","id":11}]})
Delete functionDelete function will get the selected id(s) and create JSON data and send JSON data to Java server-side for handle.
/************************************************************ * Action - delete * start to handle delete function * need confirm to delete ************************************************************/ function doDel(){ var m = grid.getSelections(); if(m.length > 0) { Ext.MessageBox.confirm('Message', 'Do you really want to delete it?' , doDel2); } else { Ext.MessageBox.alert('Message', 'Please select at least one item to delete'); } } function doDel2(btn) { if(btn == 'yes') { var m = grid.getSelections(); var jsonData = "["; for(var i = 0, len = m.length; i < len; i++){ var ss = "{\"id\":\"" + m[i].get("id") + "\"}"; //alert(ss); if(i==0) jsonData = jsonData + ss ; else jsonData = jsonData + "," + ss; ds.remove(m[i]); } jsonData = jsonData + "]"; ds.load({params:{start:0, limit:myPageSize, delData:jsonData}}); } }
And delete parameter to server side with JSON data like this: delData=[{"id":"5"},{"id":"6"}]
Add functionAdd function will pop-up a form dialog to let client enter information for save.
/************************************************************ * To create add new account dialog now.... ************************************************************/ function doAdd(){ var aAddInstanceDlg; if (!aAddInstanceDlg) { aAddInstanceDlg = createNewDialog("a-addInstance-dlg"); aAddInstanceDlg.addButton('Reset', resetForm, aAddInstanceDlg); aAddInstanceDlg.addButton('Save', function() { // validation now if (password_tf.getValue()!=cPassword_tf.getValue()) { password_tf.markInvalid("passwords not match"); password_tf.focus(); return; } // submit now... all the form information are submit to the server // handle response after that... if (form_instance_create.isValid()) { form_instance_create.submit({ waitMsg:'Creating new account now...', reset: false, failure: function(form_instance_create, action) { Ext.MessageBox.alert('Error Message', action.result.errorInfo); }, success: function(form_instance_create, action) { Ext.MessageBox.alert('Confirm', action.result.info); aAddInstanceDlg.hide(); ds.load({params:{start:0, limit:myPageSize}}); } }); }else{ Ext.MessageBox.alert('Errors', 'Please fix the errors noted.'); } }); var layout = aAddInstanceDlg.getLayout(); layout.beginUpdate(); layout.add('center', new Ext.ContentPanel('a-addInstance-inner', {title: 'create account'})); layout.endUpdate(); aAddInstanceDlg.show(); }; }
Java server side code to handle add function
protected ActionForward createAccount(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { Account account = AccountUtil.setAccount(request); // check condition now...validation JSONObject errors = new JSONObject(); AccountService accountService = new AccountService(); if (accountService.isUsernameExist(account.getUsername())) { errors.put("id", "username"); errors.put("msg", "this username also in use, please select another one"); } // if any validation errors if (errors.length() > 0) { // set response now with json format System.out.println("have error now..."); JsonMVCUtil.jsonErrorsResponse(errors, request, response); } else { // save this object try { account.setCreationDate(new Date()); accountService.createOrUpdate(account); JsonMVCUtil.jsonOkResponse( "You have successfully created this accout", request, response); } catch (Exception e) { JsonMVCUtil .jsonFailResponse("Internal Error, please try again", request, response); } } return null; }
Update functionUser will select one of rows in the list and double click this row. Update function will fetch the data from server-side by user selected id and show the result in dialog form for client to update. When user update the form information and submit the result to server, there have 2 kinds of validation, one is client side (isValid and markInvalid), another is from server side during update failed (JSON data).
In general, it need transfer a hidden "id" to server side for update. We can put this id (and any hidden fields) as one of params during submit form.
/************************************************************ * Action - update * handle double click * user select one of the item and want to update it ************************************************************/ grid.on('rowdblclick', function(grid, rowIndex, e) { var selectedId = ds.getAt(rowIndex).id; // Get information from DB and set form now... // Only need to use a ScriptTagProxy if the URL is at another domain var account_data = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({url:'/yuiExt/listAccount.do?action=loadData&id=' + selectedId}), reader: new Ext.data.JsonReader({},['id','firstname','password','username','lastname']), remoteSort: false }); account_data.on('load', function() { // set value now var newRec = account_data.getAt(0); var updateId = newRec.data['id']; username_show.setValue(newRec.get('username')); firstname_show.setValue(newRec.get('firstname')); lastname_show.setValue(newRec.get('lastname')); password_show.setValue(newRec.get('password')); cPassword_show.setValue(newRec.get('password')); var updateInstanceDlg; if (!updateInstanceDlg) { updateInstanceDlg = createNewDialog("a-updateInstance-dlg"); updateInstanceDlg.addButton('Save', function() { // validation now if (password_show.getValue()!=cPassword_show.getValue()) { password_show.markInvalid("passwords not match"); password_show.focus(); return; } // submit now... all the form information are submit to the server // handle response after that... if (form_instance_update.isValid()) { form_instance_update.submit({ params:{id : updateId}, waitMsg:'Updating this account now...', reset: false, failure: function(form_instance_update, action) { Ext.MessageBox.alert('Error Message', action.result.errorInfo); }, success: function(form_instance_update, action) { Ext.MessageBox.alert('Confirm', action.result.info); updateInstanceDlg.hide(); ds.load({params:{start:0, limit:myPageSize}}); } }); }else{ Ext.MessageBox.alert('Errors', 'Please fix the errors noted.'); } }); var layout = updateInstanceDlg.getLayout(); layout.beginUpdate(); layout.add('center', new Ext.ContentPanel('a-updateInstance-inner', {title: 'Update Account'})); layout.endUpdate(); updateInstanceDlg.show(); } }); account_data.load(); });
This is the JSON data transfer from server-side.
([{"lastname":"11","password":"12","firstname":"11-12345","enterDate":"Jun 16, 2007","username":"ffzhuang","id":40}]);
Handle JSON data in Java server sideTo create a JSON object in server side with Java. We can use the lib in "json.org". It provides a quick API to parse POJO and list etc. See the following example code:
public JSONObject toJSONObject() throws Exception { JSONObject json = new JSONObject(); json.put("totalCount", totalCount); JSONArray jsonItems = new JSONArray(); for (Iterator iter = results.iterator(); iter.hasNext();) { jsonItems.put(iter.next().toJSONObject()); } json.put("results", jsonItems); return json; }
To parse JSON data from JS in serve side, please see the following example:
JSONArray jsonArray = JsonUtil.getJsonArray(jsonString); // JsonUtil.getJsonArray(jsonString) just do this -> // jsonArray = new JSONArray(jsonString); // loop through - get from json and update for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String id = jsonObject.getString("id"); }
Here is the general JSON response Java function. You need set the ContentType as application/x-json type.
public static void jsonResponse(JSONObject jsonData, HttpServletRequest request, HttpServletResponse response) throws Exception { // check whether it is script Tag... // which is called by JSON boolean scriptTag = false; String cb = request.getParameter("callback"); if (cb != null) { scriptTag = true; response.setContentType("text/javascript"); } else { response.setContentType("application/x-json"); } PrintWriter out = response.getWriter(); if (scriptTag) { out.write(cb + "("); } response.getWriter().print(jsonData); if (scriptTag) { out.write(");"); } }
Here is the class to load data and create a JSON response to fill the form
private ActionForward loadData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // get id first String accountId = (String) request.getParameter("id").trim(); AccountService accountService = new AccountService(); Account account = accountService.loadAccountById(new Long(accountId)); // push data back to Ajax page JsonMVCUtil.jsonResponse(account.toJSONObject(), request, response); return null; }
Here is my POJO account class
public class Account extends BaseObject { private static final long serialVersionUID = -2384479668303690161L; private String username = null; private String password = null; private String firstName = ""; private String lastName = ""; private String phone = ""; private String emailAddress = ""; private Date creationDate = new Date(); private String activeYN = "active"; // get set function /** * This will create a JSON object and output to client. Get the data from * database and display result to GUI * * @return * @throws Exception */ public JSONObject toJSONObject() throws Exception { String enterDateString = DateUtil .format(creationDate, "MMM dd, yyyy"); JSONObject json = new JSONObject(); json.put("username", username); json.put("password", password); json.put("firstname", firstName); json.put("id", id); json.put("lastname", lastName); json.put("enterDate", enterDateString); return json; } }
What's Next?As always, the API documentation and examples are a great way to learn how to tweak this form to fit your needs.
Categories: Tutorial | Grid | Forms | Dialog