在WEB应用中,大部分的页面都可以被分为:列表,创建,读取,更新,删除.在Ext的文档中心提供了一个非常好的例子,一个行内编辑的表格.然而,在现实中,行内编辑的表格是远远不够的,还需要用不同的方式来展示表单.下面的例子中向你展示如何在表格中创建/更新一个对话框表单。
签于现在网上多数的Form的例子都多数是描述前台UI的,而没有对与服务端通讯的部分,故参考EXTJS的一个指南,写下此文,希望能对大家有所帮助.
在WEB应用中,大部分的页面都可以被分为:列表,创建,读取,更新,删除.在Ext的文档中心提供了一个非常好的例子,一个行内编辑的表格.然而,在现实中,行内编辑的表格是远远不够的,还需要用不同的方式来展示表单.下面的例子中向你展示如何在表格中创建/更新一个对话框表单.
列表功能
首先是是一个权限列表页,它包含分页,查询/过滤功能,创建和删除功能.
先定义数据源:
this.ds = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({ url : '/wit/data.shtml' }), //'/wit/data.shtml' 一个读取数据列表的Action
reader : new Ext.data.JsonReader({ //使用JSON传输入数据
root : 'roleList',
totalProperty : 'totalCount',
id : 'id'
},
// 定义字段映射
[
{
name : 'id',
mapping : 'id',
type : 'string'
},
{
name : 'name',
mapping : 'name',
type : 'string'
},
{
name : 'description',
mapping : 'description',
type : 'string'
},
{
name : 'createDate',
mapping : 'createDate',
type : 'string'
},
{
name : 'updateDate',
mapping : 'updateDate',
type : 'string'
}
]),
remoteSort : true
});
this.ds.load({ params:{ start : 0, limit : 20 } });
指定数据的来源位置,解析的方式,以及字段的映射.
接下来是表格中表头的定义,匹配上面的字段:
this.cm = new Ext.grid.ColumnModel([
{
header : '#',
dataIndex : 'id',
width : 30,
sortable : 1
},
{
header : '名称',
dataIndex : 'name',
width : 140,
sortable : 1
},
{
header : '描述',
dataIndex : 'description',
width : 140,
sortable : 1
},
{
header : '创建日期',
dataIndex : 'createDate',
width : 150,
sortable : 1
},
{
header : '修改日期',
dataIndex : 'updateDate',
width : 150,
sortable : 1
}
]);
再定义一下Grid:
this.grid = new Ext.grid.Grid('htmlGridPanel', { ds : Grid.ds, cm : Grid.cm, enableColLock : false, autoSizeColumns : true, loadMask : true }); this.grid.render();
现在,就可以看到简单的表格了.功能还有待完善.
接下来,在表格的头部面板处,添加过滤/查询的下拉菜单:
this.gridHead = this.grid.getView().getHeaderPanel(true); this.toolbar = new Ext.Toolbar(this.gridHead); this.filterBtn = new Ext.Toolbar.MenuButton({ icon : '../images/class.gif', cls : 'x-btn-text-icon', text : '选择过滤器', tooltip : '选择一个过滤器', menu : { items : [ new Ext.menu.CheckItem({ text : '编号', value : 'id', checked : true, group : 'filter', checkHandler : this.onItemCheck}), new Ext.menu.CheckItem({ text : '名称', value : 'name', checked : false, group : 'filter', checkHandler : this.onItemCheck}), new Ext.menu.CheckItem({ text : '描述', value : 'description', checked : false, group : 'filter', checkHandler : this.onItemCheck}) ]}, minWidth : 105 }); this.toolbar.add(this.filterBtn); this.filter = Ext.get(this.toolbar.addDom({ tag : 'input', type : 'text', size : '30', value : '', style : 'background : #F0F0F9;' }).el); this.filter.on('keypress', function(e) { if (e.getKey() == e.ENTER && this.getValue().length > 0) { Grid.ds.load({ params : { start : 0, limit : 20 }}); } });
在表格的底部面板添加分页,添加,删除按钮:
this.gridFoot = this.grid.getView().getFooterPanel(true); this.paging = new Ext.PagingToolbar(this.gridFoot, this.ds, { pageSize : 20, displayInfo : true, displayMsg : '共有 {2} 条记录.当前显示 {0} - {1}条记录.', emptyMsg : '没有记录!' }); this.paging.add('-', { pressed : true, enableToggle : true, text : '添加', cls : '', toggleHandler : this.doAdd }); this.paging.add('-', { pressed : true, enableToggle : true, text : '删除', cls : '', toggleHandler : this.doDel });在分页中,你需要在从服务器端加载数据之前发送过滤的字段和值:
this.ds.on('beforeload', function() {
Grid.ds.baseParams = {
filterValue : Grid.filter.getValue(),
filterTxt : Grid.filterBtn.getText()
};
});
从服务器端返回的列表的JSON结果如下:
{"roleList":[{"id":21,"description":"description21","name":"puras21","createDate":"Fri Sep 07 15:54:44 CST 2007","updateDate":"Fri Sep 07 15:54:44 CST 2007"},{"id":40,"description":"description40","name":"puras40","createDate":"Fri Sep 07 15:54:44 CST 2007","updateDate":"Fri Sep 07 15:54:44 CST 2007"}],"totalCount":2}
删除
删除方法如下:
doDel : function() { var c = Grid.grid.getSelections(); if (c.length > 0) Ext.MessageBox.confirm('消息', '确认要删除所选记录?', Grid.doDelProc); else Ext.MessageBox.alert('警告', '最少需要选择一条记录!'); }, doDelProc : function(btn) { if (btn == 'yes') { if (Grid.grid.getSelectionModel().hasSelection()) { var ids = new Array(); var records = Grid.grid.getSelectionModel().getSelections(); for (var i = 0, len = records.length; i < len; i++) { ids[ids.length] = records[i].id; } Ext.lib.Ajax.request( 'GET', '/wit/delete.shtml?ids=' + ids, { success : Grid.onSuccess, failure : function(form, action) { Ext.MessageBox.alert('消息', '删除失败!');} }, null ); } } }, onSuccess : function(o) { var response = function(json) { try { return eval('(' + json + ')'); } catch(e) {} return null; }(o.responseText); if (response.failure && response.failure == true) { Ext.MessageBox.alert('消息', response.info); } Grid.ds.reload(); }
通过Ajax的形式提交到服务器端.如果删除失败,则将失败信息显示给用户.onSuccess可以用于添,删,改三个功能的处理.返回的JSON数据结构如下:
"{success : true, info : '删除成功!'}"
创建
在这里,创建和修改者是用Dialog的形式来做的,首先则需要创建相应的DIV:
<!-- add div -->
<div id="a-addInstance-dlg" style="visibility:hidden;">
<div class="x-dlg-hd">添加权限</div>
<div class="x-dlg-bd">
<div id="a-addInstance-inner" class="x-layout-inactive-content">
<div id="a-addInstance-form"></div>
</div>
</div>
</div>
之后就是在这个DIV里创建Form了,直接用Ext的Form组件:
createNewForm : function() {
this.name_tf = new Ext.form.TextField({
fieldLabel : '名称',
name : 'name',
allowBlank : false
});
this.description_tf = new Ext.form.TextField({
fieldLabel : '描述',
name : 'description'
});
this.addForm = new Ext.form.Form({
labelAlign : 'right',
url : '/wit/add.shtml'
});
this.addForm.column({
width : 430,
labelWidth : 120,
style : 'margin-left : 8px; margin-top : 8px;'
});
this.addForm.fieldset(
{id : 'desc', legend : '请填写字段值'},
Grid.name_tf,
Grid.description_tf
);
this.addForm.applyIfToFields({ width : 255 });
this.addForm.render('a-addInstance-form');
this.addForm.end();
}
之后别忘了在加载的时候调用这个方法:
this.createNewForm();
Form窗体定义完,现在可以处理前面说的过那个创建按钮的事件了,在这里事件处理的方法名为doAdd:
doAdd : function() { if (!Grid.addInstanceDlg) { Grid.addInstanceDlg = Grid.createNewDialog('a-addInstance-dlg'); Grid.addInstanceDlg.addButton('重置', Grid.resetForm, Grid.addInstanceDlg); Grid.addInstanceDlg.addButton('保存', Grid.saveNewForm, Grid.addInstanceDlg); var layout = Grid.addInstanceDlg.getLayout(); layout.beginUpdate(); var t = new Ext.ContentPanel('a-addInstance-inner', {title : 'create account'}); layout.add('center', new Ext.ContentPanel('a-addInstance-inner', {title : '添加权限'})); layout.endUpdate(); } Grid.addInstanceDlg.show(); }
首先用Grid.createNewDialog创建一个LayoutDialog,之后再把添加里的特有的按钮加上去,然后更新一下Dialog的布局,把它显示出来,这时就可以看到添加的窗体了:
Grid.createNewDialog用于创建和修改时创建对话框,代码如下:
createNewDialog : function(title) { var newDialog = new Ext.LayoutDialog(title, { modal : true, autoTabs : true, proxyDrag : true, resizable : false, width : 480, height : 302, shadow : true, center : { autoScroll : true, tabPosition : 'top', closeOnTab : true, closeOnTab : true, alwaysShowTabs : false } }); newDialog.addKeyListener(27, newDialog.hide, newDialog); newDialog.addButton('取消', function() { newDialog.hide(); } ); return newDialog; }
如果添加成功,则自动关闭这个Dialog,并重新加载列表,如果添加失败,只是简单的弹出一个对话框,提示失败,其实这里可以做的更人性化一些,可以在服务器端传回错误的原因,比如某字段有问题,可以红色显示出其输入框等等.这里服务端返回的JSON数据与删除返回的一样.
处理代码如下:
saveNewForm : function() {
if (Grid.addForm.isValid()) {
Grid.addForm.submit({
waitMsg : '正在保存数据...',
reset : true,
failure : function(form, action) {
Ext.MessageBox.alert('友情提示', action.result.info);
},
success : function(form, action) {
Grid.addInstanceDlg.hide();
Grid.ds.reload();
}
});
} else {
Ext.MessageBox.alert('错误', '字段填写不正确!');
Grid.name_tf.focus();
}
}
修改
修改则和创建差不多了,不同的有两点,一是事件是在列表的行上双击,来触发事件,弹出修改对话框,另一个则是需要在显示对话框的同时,把所要修改的记录的数据加载进来.
首先在列表加上事件捕捉:
this.grid.on('rowdblclick', this.onRowDbClick, this);
下面则是处理这个事件的代码:
onRowDbClick : function(grid, rowIndex, e) { var selectId = this.ds.data.items[rowIndex].id; var roleData = new Ext.data.Store({ proxy : new Ext.data.HttpProxy({url : '/wit/edit.shtml?id=' + selectId}), reader : new Ext.data.JsonReader({}, ['id', 'name', 'description']), remoteSort : false }); roleData.on('load', function() { Grid.updateId = roleData.getAt(0).data['id']; Grid.name_show.setValue(roleData.getAt(0).data['name']); Grid.description_show.setValue(roleData.getAt(0).data['description']); if (!Grid.updateInstanceDlg) { Grid.updateInstanceDlg = Grid.createNewDialog('a-updateInstance-dlg'); Grid.updateInstanceDlg.addButton('保存', Grid.saveUpdateForm, Grid.updateInstanceDlg); var layout = Grid.updateInstanceDlg.getLayout(); layout.beginUpdate(); layout.add('center', new Ext.ContentPanel('a-updateInstance-inner', {title : '修改权限'})); layout.endUpdate(); } Grid.updateInstanceDlg.show(); }); roleData.load(); }
这里做了两件事,一个是把欲修改的数据加载到本地, 服务端返回的数据结构为:
([{"id":"12","description":"test role 12","name":"puras 12"}])
一个是将数据置入Form窗体的字段中,并将Dialog显示出来.修改的Form与创建的相似:
createEditForm : function() { this.name_show = new Ext.form.TextField({ fieldLabel : '名称', name : 'name', allowBlank : false }); this.description_show = new Ext.form.TextField({ fieldLabel : '名称', name : 'description' }); this.editForm = new Ext.form.Form({ labelAlign : 'right', url : '/wit/edit_ok.shtml' }); this.editForm.column({width : 430, labelWidth : 120, style : 'margin-left : 8px; margin-top : 8px;'}); this.editForm.fieldset( {legend : '请更新字段值'}, Grid.name_show, Grid.description_show ); this.editForm.applyIfToFields({width : 255}); this.editForm.render('a-updateInstance-form'); this.editForm.end(); }
这个Form对应的Div为:
<!-- update div -->
<div id="a-updateInstance-dlg" style="visibility:hidden;">
<div class="x-dlg-hd">修改权限</div>
<div class="x-dlg-bd">
<div id="a-updateInstance-inner" class="x-layout-inactive-content">
<div id="a-updateInstance-form"></div>
</div>
</div>
</div>
双击某条记录,则会弹出修改Dialog了
修改的处理事件与添加类似,需要注意的地方就是ID是怎么传过去的:
saveUpdateForm : function() { if (Grid.editForm.isValid()) { Grid.editForm.submit({ params : { id : Grid.updateId}, waitMsg : '正在更新数据...', reset : false, failure : function(form, action) { Ext.MessageBox.alert('友情提示', action.result.info); }, success : function(form, action) { Grid.updateInstanceDlg.hide(); Grid.ds.reload(); } }); } else { Ext.MessageBox.alert('错误', '字段填写不正确!'); } }到此就Over啦,列表,添,删,改都OK了.在没有做的时候,总是感觉找不到入口点,做完之后才发现,原来自己担心的问题,都不是问题,哈,想想,还是挺简单的.