【ExtJs】表格控件Grid的增删改查,利用renderer让操作列actioncolumn使用文字而不是图标

在《【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 "删除成功!";
?>


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。