在《【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 οnclick='editRow(this)' href='javascript:void(0);' id="+record.data["id"]+" username="+record.data["username"]+" password="+record.data["password"]+">编辑</a> <a οnclick='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 οnclick='editRow(this)' href='javascript:void(0);' id="+record.data["id"]+" username="+record.data["username"]+" password="+record.data["password"]+">编辑</a> <a οnclick='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 "删除成功!";
?>