在《【ExtJs】与后台数据库交互的带分页表格组件grid的查询》(点击打开链接)中介绍了Grid控件是怎么分页显示的。再加上对此控件内的数据的增加、删除、修改,就真的是大功告成了。此控件的排序,应该在后台的数据库查询语句中增加一条order by语句即可,前台的排序在分页之后,仅能对当前页进行排序,没有什么意义。下面举一个例子来说明,如果对ExtJs的表格控件Grid进行增删改查
一、基本目标
还是在数据库中有一张user表:
然后在网页中,如下图所示,通过增加、编辑、删除按钮能为这个表格控件进行增删改查。
二、基本思想
此工程的目录结构如下图:
三、制作过程
1、showData.php
这个页面就是《【ExtJs】与后台数据库交互的带分页表格组件grid的查询》(点击打开链接)中,那个读取数据的formSubmit.php,一字未改,把数据,从model.php的类读出来。并且完成分页数据的构造。这里不再赘述。
<?php $start=$_REQUEST["start"]; $limit=$_REQUEST["limit"]; include_once("model.php"); $userClass=new userClass(); $user=$userClass->getUserInfoByPaging($start,$limit); $total=$userClass->getUserTotalNum(); $data=""; for($i=0;$i<count($user);$i++){ $data.="{'id':".$user[$i]['id'].",'username':'".$user[$i]['username']."','password':'".$user[$i]['password']."'}"; if(($i+1)!=count($user)){ $data.=","; } } echo "{ 'success':true, 'total':{$total}, 'data':[{$data}] }"; ?>2、model.php
这个页面也没有怎么修改,根据《【php】利用原生态的JavaScript Ajax为php进行MVC分层设计,兼容IE6》(点击打开链接)的思想,仅仅是为insert into,delete from,update等无结果返回的语句多添加了一个方法,其实这个文件就是user这张表的业务逻辑。
<?php function createCon(){ //数据库的地址是localhost:3306,数据库用户名(第二项)是root,数据库密码(第三项)是root $con=mysql_connect("localhost","root","root"); if(!$con){ die("连接失败!"); } //要操作test数据库 mysql_select_db("test",$con); //防止乱码 mysql_query("set names utf8;"); return $con; } class userClass{ public function getUserTotalNum(){ $con=createCon(); $result=mysql_query("select count(*) as total from user;"); $row=mysql_fetch_array($result); mysql_close($con); return $row['total']; } public function getUserInfoByPaging($start,$limit){ $con=createCon(); $result=mysql_query("select * from user order by id;");//这里按照id排列,如果需要其他排序自己修改 $userList=array(); for($i=0;$row=mysql_fetch_array($result);$i++){ $userList[$i]['id']=$row['id']; $userList[$i]['username']=$row['username']; $userList[$i]['password']=$row['password']; } $user=array(); for($i=0,$j=$start;$j<($start+$limit);$i++,$j++){ if(empty($userList[$j])){ break; } $user[$i]=$userList[$j]; } mysql_close($con); return $user; } public function modify($sql){ //对于那些传sql过来没有返回结果的方法,归纳到同一类 $con=createCon(); mysql_query($sql); mysql_close($con); } } ?>
3、Grid.html
前端,虽然仅一个Grid.html页面,但是这个页面相当宏大
(1)首先引入Ext资源,然后与《【ExtJs】与后台数据库交互的带分页表格组件grid的查询》(点击打开链接)一样,先定义模型并且根据构造数据中心。这里的定义写在Ext.onReady(function(){});函数之外作为全局变量。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>ExtGrid</title> <script type="text/javascript" src="../js/ext-all.js"></script> <script type="text/javascript" src="../js/bootstrap.js"></script> <script type="text/javascript" src="../js/ext-lang-zh_CN.js"></script> <link href="../ext-theme-classic/ext-theme-classic-all.css" rel="stylesheet" type="text/css"> </head> <body> </body> </html> <script> Ext.define('user',{ extend:'Ext.data.Model', fields:[ {name:'id',type:'int'}, {name:'username',type:'string'}, {name:'password',type:'string'} ] }); var userStore=Ext.create('Ext.data.Store',{ model:'user', pageSize:5,//每页显示数目 proxy:{ type:'ajax', url:'showData.php',//提供Json字符串的页面 reader:{ type:'json', root:'data', totalProperty:'total'//总项数 } }, autoLoad:true });
(2)之后是相当宏大的表格控件Grid的声明。右上角的“增加”按钮,使用了ExtJs的表单技术,这个东西在《【ExtJs】ExtJs的表单插件与表单布局、提交与验证》(点击打开链接)已经详细讲过,这里不再赘述。一会儿表单的处理页面是addData.php。
如果要在表格控件中的操作列actioncolumn使用文字而不是图标,则应该直接使用渲染器renderer来构造此列,而不是用一个xtype指明此乃操作列。你想要在渲染器renderer的函数中,要哪列的数据,直接通过record.data["xx"]来取,其中xx是上面的dataIndex,然后把你在此列的构造东西,直接放在返回值即可。因为这里的编辑超级链接,需要三个参数去构造表单中的,因此这次使用到《【JavaScript】body内的任意节点的自定义属性》(点击打开链接)的方式,把id,username,password,这三个参数藏在a标签的自定义属性中,利用editRow(this),传递到之后的onclick处理JS函数editRow(obj)中。因此这里在返回值字符串中的editRow中写太多参数,会导致这个字符串错乱。因此改用这种方式。
Ext.onReady(function(){ Ext.QuickTips.init(); Ext.form.Field.prototype.msgTarget = 'side'; //以上这两行代码,声明表单错误验证的信息 Ext.create('Ext.grid.Panel',{ title:'用户信息表', renderTo: Ext.getBody(), store:userStore,//此表格控件的数据由userStore数据中心提供支持 tools:[{//右上角的按钮通过tools来构造 xtype:'button', text:'增加', listeners: { click: function(){//点击这个按钮将显出一个表单,给用户填写添加数据。 var form1 = Ext.create('Ext.form.Panel', { width: 400, method: 'POST', layout: 'anchor', title: '编辑', items: [{ fieldLabel: '用户名', xtype: 'textfield', name: 'username', allowBlank: false, anchor: '95%' }, { fieldLabel: '密码', xtype: 'textfield', allowBlank: false, name: 'password', regex: /^[A-Za-z]+$/,//正则表达式 regexText: '除英文字符以外,不得有其他字符!', anchor: '95%' }], bbar: [{ xtype: 'tbfill' }, { xtype: 'button', text: '确定', disabled: true, formBind: true, listeners: { click: function(){ var thisForm = form1.getForm(); thisForm.submit({ url: "addData.php", success: function(form, action){ userStore.reload(); window1.close(); Ext.Msg.alert('Success', action.result.msg); } }); } } }, { xtype: 'button', text: '关闭', listeners: { click: function(){ window1.close();//这里windows1使用close()销毁方法,而不是hide(),因为每次点击都会重新声明一个window1 } } }, { xtype: 'tbfill' }] }); var window1=Ext.create('Ext.window.Window', { renderTo: Ext.getBody(), header: false, border: false, //没有边框 resizable: false, //不可以自由调整大小,默认可以 width: 400, items:[form1] }); window1.show(); } } }], columns:[//之后是每一列存放的东西 {text:'ID',dataIndex:'id',flex:1}, {text:'用户名',dataIndex:'username',flex:1}, {text:'密码',dataIndex:'password',flex:1}, {//如果要让操作列不是图标,而是使用文字则这样声明 text:'操作', flex:1, renderer:function(value,cellmeta,record,rowIndex,columnIndex,store){ return "<a onclick='editRow(this)' href='javascript:void(0);' id="+record.data["id"]+" username="+record.data["username"]+" password="+record.data["password"]+">编辑</a> <a onclick='deleteRow(this)' href='javascript:void(0);' id="+record.data["id"]+">删除</a>" } }], bbar:{ xtype:'pagingtoolbar',//底部工具栏是分页工具栏 store:userStore,//按照userStore的数据进行分页 displayInfo:true//显示共XX页,每页显示XX条的信息 } }); });(3)其后是写在Ext.onReady(function(){});函数之外editData(obj)JS函数,同样与tools中的“增加”按钮的监听器一样,构造一个表单,只是个表单的value早已存放好改列的所有信息,通过obj.id,obj.username,obj.password的方法来取。一会儿表单的处理页面是editData.php。同时,这里由于显示的id是不可用域disabled:true,因此要再声明一个隐藏域,否则因为HTML的表单提交,默认是不把disaled:true不可用域的内容带过去的,editData.php会由于id哪项disabled:true接不到id这个参数,补个隐藏域刚刚好。
function editRow(obj){ var id=obj.id; var username=obj.username; var password=obj.password; var form1 = Ext.create('Ext.form.Panel', { width: 400, method: 'POST', layout: 'anchor', title: '编辑', items: [{ fieldLabel: 'ID', xtype: 'textfield', disabled: true, value: id, anchor: '95%' },{ xtype: 'hidden', name: 'id', value: id }, { fieldLabel: '用户名', xtype: 'textfield', name: 'username', allowBlank: false, value: username, anchor: '95%' }, { fieldLabel: '密码', xtype: 'textfield', allowBlank: false, name: 'password', value: password, regex: /^[A-Za-z]+$/,//正则表达式 regexText: '除英文字符以外,不得有其他字符!', anchor: '95%' }], bbar: [{ xtype: 'tbfill' }, { xtype: 'button', text: '确定', disabled: true, formBind: true, listeners: { click: function(){ var thisForm = form1.getForm(); thisForm.submit({ url: "editData.php", success: function(form, action){ userStore.reload(); window1.close(); Ext.Msg.alert('Success', action.result.msg); } }); } } }, { xtype: 'button', text: '关闭', listeners: { click: function(){ window1.close(); } } }, { xtype: 'tbfill' }] }); var window1=Ext.create('Ext.window.Window', { renderTo: Ext.getBody(), header: false, border: false, //没有边框 resizable: false, //不可以自由调整大小,默认可以 width: 400, items:[form1] }); window1.show(); };(4)删除的Js函数同理了,这里不再赘述。只是这里根本就不需要用户填写什么,因此直接通过《【ExtJs】ExtJs的Ajax》(点击打开链接)的方式,让deleteData.php这个页面完成工作。
function deleteRow(obj){ var id=obj.id; Ext.MessageBox.confirm("警告", "你确认要删除吗?改操作不能撤销!", function (btn) { if(btn=='yes'){ Ext.Ajax.request({ url: 'deleteData.php', params: { id:id }, method: 'POST', success: function (response, options) { Ext.MessageBox.alert('成功', response.responseText); userStore.reload(); }, failure: function (response, options) { Ext.MessageBox.alert('失败', '请求超时或网络故障,错误编号:' + response.status); } }); } }); }
因此整个Grid.html的页面是这个样子的,关键是所有增删改查的表单完成工作之后,补一句userStore.reload()方法,刷新数据中心,让前台的数据中心再于后台数据库取数字,通过Ajax的方法更新整个Grid的内容:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>ExtGrid</title> <script type="text/javascript" src="../js/ext-all.js"></script> <script type="text/javascript" src="../js/bootstrap.js"></script> <script type="text/javascript" src="../js/ext-lang-zh_CN.js"></script> <link href="../ext-theme-classic/ext-theme-classic-all.css" rel="stylesheet" type="text/css"> </head> <body> </body> </html> <script> Ext.define('user',{ extend:'Ext.data.Model', fields:[ {name:'id',type:'int'}, {name:'username',type:'string'}, {name:'password',type:'string'} ] }); var userStore=Ext.create('Ext.data.Store',{ model:'user', pageSize:5,//每页显示数目 proxy:{ type:'ajax', url:'showData.php',//提供Json字符串的页面 reader:{ type:'json', root:'data', totalProperty:'total'//总项数 } }, autoLoad:true }); Ext.onReady(function(){ Ext.QuickTips.init(); Ext.form.Field.prototype.msgTarget = 'side'; //以上这两行代码,声明表单错误验证的信息 Ext.create('Ext.grid.Panel',{ title:'用户信息表', renderTo: Ext.getBody(), store:userStore,//此表格控件的数据由userStore数据中心提供支持 tools:[{//右上角的按钮通过tools来构造 xtype:'button', text:'增加', listeners: { click: function(){//点击这个按钮将显出一个表单,给用户填写添加数据。 var form1 = Ext.create('Ext.form.Panel', { width: 400, method: 'POST', layout: 'anchor', title: '编辑', items: [{ fieldLabel: '用户名', xtype: 'textfield', name: 'username', allowBlank: false, anchor: '95%' }, { fieldLabel: '密码', xtype: 'textfield', allowBlank: false, name: 'password', regex: /^[A-Za-z]+$/,//正则表达式 regexText: '除英文字符以外,不得有其他字符!', anchor: '95%' }], bbar: [{ xtype: 'tbfill' }, { xtype: 'button', text: '确定', disabled: true, formBind: true, listeners: { click: function(){ var thisForm = form1.getForm(); thisForm.submit({ url: "addData.php", success: function(form, action){ userStore.reload(); window1.close(); Ext.Msg.alert('Success', action.result.msg); } }); } } }, { xtype: 'button', text: '关闭', listeners: { click: function(){ window1.close();//这里windows1使用close()销毁方法,而不是hide(),因为每次点击都会重新声明一个window1 } } }, { xtype: 'tbfill' }] }); var window1=Ext.create('Ext.window.Window', { renderTo: Ext.getBody(), header: false, border: false, //没有边框 resizable: false, //不可以自由调整大小,默认可以 width: 400, items:[form1] }); window1.show(); } } }], columns:[//之后是每一列存放的东西 {text:'ID',dataIndex:'id',flex:1}, {text:'用户名',dataIndex:'username',flex:1}, {text:'密码',dataIndex:'password',flex:1}, {//如果要让操作列不是图标,而是使用文字则这样声明 text:'操作', flex:1, renderer:function(value,cellmeta,record,rowIndex,columnIndex,store){ return "<a onclick='editRow(this)' href='javascript:void(0);' id="+record.data["id"]+" username="+record.data["username"]+" password="+record.data["password"]+">编辑</a> <a onclick='deleteRow(this)' href='javascript:void(0);' id="+record.data["id"]+">删除</a>" } }], bbar:{ xtype:'pagingtoolbar',//底部工具栏是分页工具栏 store:userStore,//按照userStore的数据进行分页 displayInfo:true//显示共XX页,每页显示XX条的信息 } }); }); function editRow(obj){ var id=obj.id; var username=obj.username; var password=obj.password; var form1 = Ext.create('Ext.form.Panel', { width: 400, method: 'POST', layout: 'anchor', title: '编辑', items: [{ fieldLabel: 'ID', xtype: 'textfield', disabled: true, value: id, anchor: '95%' },{ xtype: 'hidden', name: 'id', value: id }, { fieldLabel: '用户名', xtype: 'textfield', name: 'username', allowBlank: false, value: username, anchor: '95%' }, { fieldLabel: '密码', xtype: 'textfield', allowBlank: false, name: 'password', value: password, regex: /^[A-Za-z]+$/,//正则表达式 regexText: '除英文字符以外,不得有其他字符!', anchor: '95%' }], bbar: [{ xtype: 'tbfill' }, { xtype: 'button', text: '确定', disabled: true, formBind: true, listeners: { click: function(){ var thisForm = form1.getForm(); thisForm.submit({ url: "editData.php", success: function(form, action){ userStore.reload(); window1.close(); Ext.Msg.alert('Success', action.result.msg); } }); } } }, { xtype: 'button', text: '关闭', listeners: { click: function(){ window1.close(); } } }, { xtype: 'tbfill' }] }); var window1=Ext.create('Ext.window.Window', { renderTo: Ext.getBody(), header: false, border: false, //没有边框 resizable: false, //不可以自由调整大小,默认可以 width: 400, items:[form1] }); window1.show(); }; function deleteRow(obj){ var id=obj.id; Ext.MessageBox.confirm("警告", "你确认要删除吗?改操作不能撤销!", function (btn) { if(btn=='yes'){ Ext.Ajax.request({ url: 'deleteData.php', params: { id:id }, method: 'POST', success: function (response, options) { Ext.MessageBox.alert('成功', response.responseText); userStore.reload(); }, failure: function (response, options) { Ext.MessageBox.alert('失败', '请求超时或网络故障,错误编号:' + response.status); } }); } }); } </script>
之后是各个数据库处理页面,没什么好说的,就是接住前台ExtJs传来数据,利用php对Mysql的操作,然后本页面打印好响应的Json,ExtJs通过自身的Ajax机制,读到这个字符串,会自动处理。借助前台ExtJs传来数据,当然,这里如果真正拿去开系统,还需要防范SQL注入,这里仅仅是小例子,就不要写这么复杂了。
4、addData.php插入数据后端页面
<?php $username=$_REQUEST["username"]; $password=$_REQUEST["password"]; include_once("model.php"); $userClass=new userClass(); $userClass->modify("insert into user(username,password) values('".$username."','".$password."');"); echo "{ 'success':true, 'msg':'添加成功!' }"; ?>5、editData.php
修改数据后端页面
<?php $id=$_REQUEST["id"]; $username=$_REQUEST["username"]; $password=$_REQUEST["password"]; include_once("model.php"); $userClass=new userClass(); $userClass->modify("update user set username='".$username."' where id=".$id.";"); $userClass->modify("update user set password='".$password."' where id=".$id.";"); echo "{ 'success':true, 'msg':'修改成功!' }"; ?>6、deleteData.php
删除数据后端页面,其实一般不这样做的,按理说,对于数据库的所有删除数据的操作都是标记删除的,到时候如果遇到紧急情况或者需要数据分析的情况,可以翻查记录。正如监控录像一样,直接删除数据,太业余了,不过这里仅仅是小例子,不要在乎这些细节!
由于这里是ExtJs的Ajax处理,而不是表单,因此打印出一个平常的字符串即可!
<?php $id=$_REQUEST["id"]; include_once("model.php"); $userClass=new userClass(); $userClass->modify("delete from user where id=".$id.";"); echo "删除成功!"; ?>
【ExtJs】表格控件Grid的增删改查,利用renderer让操作列actioncolumn使用文字而不是图标
原文地址:http://blog.csdn.net/yongh701/article/details/45456761