.net mvc extjs 操作数组gridpanel 从控制器得到数组传给视图中的gridoanel 实现extjs表格

> Extjs4.2 Grid搜索Ext.ux.grid.feature.Searching使用介绍
Extjs4.2 Grid搜索Ext.ux.grid.feature.Searching使用介绍
Extjs4.2 默认提供的Search搜索,功能还是非常强大的,只是对于国内的用户来说,还是不习惯在每列里面单击好几下再筛选,于是相当当初2.2里面的搜索,更加的实用点,于是在4.2里面实现。
国际惯例,先上图
国外的大牛已经帮我们实现了在4.0中的应用,但是到4.2还需要做少许变更才可以使用。
修改后的源代码如下[复制如下代码,放到ux/grid/features/Searching.js]:
&&&&&&&&&&&&&&&&&&&&&&&Ext.define('Ext.ux.grid.feature.Searching',&{ &&&&&extend:&'Ext.grid.feature.Feature', &&&&&alias:&'feature.searching', &&&&&&&&&&&&&&&&&&&&&searchText:'查询', &&&&&&&&& &&&&&searchTipText:'输入关键字回车查询', &&&&&&&&&&&&&selectAllText:'所有列', &&&&&&&&&&&&&&&position:'top', &&&&&&&&&&&&&iconCls:&'Zoom', &&&&&&&&&&&&&&checkIndexes:'all', &&&&&&&&&&&&&disableIndexes:[], &&&&&&&&&&&&&&dateFormat:undefined, &&&&&&&&&&&&&showSelectAll:true, &&&&&&&&&&&&&&menuStyle:'checkbox', &&&&&&&&&&&&&&&minChars:&2, &&&&&&&&&&&&minCharsTipText:'至少输入{0}个字符', &&&&&&&&&&&&&&mode:'remote', &&&&&&&&&&&&&&&&&&&&&width:100, &&&&&&&&&&&&&paramNames:&{ &&&&&&&&&&fields:'fields'&&&&&&&&&,query:'query'&&&&&}, &&&&&&&&&&&&&shortcutKey:'r', &&&&&&&&&&&&&shortcutModifier:'alt', &&&&&&&&&&&&&align:'left', &&&&&&&&&&&&minLength:&2, &&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&init:&function&(grid)&{ &&&&&&&&&this.grid&=& &&&&&&&&&if&(this.grid.rendered) &&&&&&&&&&&&&this.onRender(); &&&&&&&&&else&&&&&&&&&&&&&this.grid.on('render',&this.onRender,&this); &&&&&}, &&&&&&onRender:function()&{ &&&&&&&&& &&&&&&&&&var&panel&=&this.toolbarContainer&||&this. &&&&&&&&&var&tb&=&'bottom'&===&this.position&?&panel.getDockedItems('toolbar[dock=&bottom&]')&:&panel.getDockedItems('toolbar[dock=&top&]'); &&&&&&&&&if(tb.length&&&0) &&&&&&&&&&&&&tb&=&tb[0] &&&&&&&&&else&{ &&&&&&&&&&&&&tb&=&Ext.create('Ext.toolbar.Toolbar',&{dock:&this.position}); &&&&&&&&&&&&&panel.addDocked(tb); &&&&&&&&&} &&&&&&&&&&&&&&&&&&&this.menu&=&Ext.create('Ext.menu.Menu'); &&&&&&&&&&&&&&&&&&&if('right'&===&this.align)&{ &&&&&&&&&&&&&tb.add('-&'); &&&&&&&&&} &&&&&&&&&else&{ &&&&&&&&&&&&&if(0&&&tb.items.getCount())&{ &&&&&&&&&&&&&&&&&tb.add('-'); &&&&&&&&&&&&&} &&&&&&&&&} &&&&&&&&&&&&&&&&&&&tb.add({ &&&&&&&&&&&&&&text:this.searchText &&&&&&&&&&&&&,menu:this.menu &&&&&&&&&&&&&,iconCls:this.iconCls &&&&&&&&&}); &&&&&&&&&&&&&&&&&&&this.field&=&Ext.create('Ext.form.TwinTriggerField',&{ &&&&&&&&&&&&&width:this.width, &&&&&&&&&&&&&qtip:&'ddd', &&&&&&&&&&&&&selectOnFocus:undefined&===&this.selectOnFocus&?&true&:&this.selectOnFocus, &&&&&&&&&&&&&triggerCls:&'x-form-clear-trigger', &&&&&&&&&&&&&&&&&&&&&&&&&&onTrigger1Click:&Ext.bind(this.onTriggerClear,&this), &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&minLength:this.minLength &&&&&&&&&}); &&&&&&&&& &&&&&&&&&&&&&&&&&&this.field.on('render',&function()&{ &&&&&&&&&&&&& &&&&&&&&&&&&&var&qtip&=&this.minChars&?&Ext.String.format(this.minCharsTipText,&this.minChars)&:&this.searchTipT &&&&&&&&&&&&&Ext.QuickTips.register({ &&&&&&&&&&&&&&&&&target:&this.field.inputEl, &&&&&&&&&&&&&&&&&text:&qtip &&&&&&&&&&&&&}); &&&&&&&&&&&&& &&&&&&&&&&&&&if(this.minChars)&{ &&&&&&&&&&&&&&&&&this.field.el.on({scope:this,&buffer:300,&keyup:this.onKeyUp}); &&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&&&var&map&=&new&Ext.KeyMap(this.field.el,&[{ &&&&&&&&&&&&&&&&&&key:Ext.EventObject.ENTER &&&&&&&&&&&&&&&&&,scope:this&&&&&&&&&&&&&&&&&,fn:this.onTriggerSearch &&&&&&&&&&&&&},{ &&&&&&&&&&&&&&&&&&key:Ext.EventObject.ESC &&&&&&&&&&&&&&&&&,scope:this&&&&&&&&&&&&&&&&&,fn:this.onTriggerClear &&&&&&&&&&&&&}]); &&&&&&&&&&&&&map.stopEvent&=&true; &&&&&&&&&},&this,&{single:true}); &&&&&&&&&&tb.add(this.field); &&&&&&&&&&&&&&&&&&&this.reconfigure(); &&&&&&&&&&&&&&&&&&&if(this.shortcutKey&&&&this.shortcutModifier)&{ &&&&&&&&&&&&&var&shortcutEl&=&this.grid.getEl(); &&&&&&&&&&&&&var&shortcutCfg&=&[{ &&&&&&&&&&&&&&&&&&key:this.shortcutKey &&&&&&&&&&&&&&&&&,scope:this&&&&&&&&&&&&&&&&&,stopEvent:true&&&&&&&&&&&&&&&&&,fn:function()&{ &&&&&&&&&&&&&&&&&&&&&this.field.focus(); &&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&}]; &&&&&&&&&&&&&shortcutCfg[0][this.shortcutModifier]&=&true; &&&&&&&&&&&&&this.keymap&=&new&Ext.KeyMap(shortcutEl,&shortcutCfg); &&&&&&&&&} &&&&&&&&&&if(true&===&this.autoFocus)&{ &&&&&&&&&&&&&this.grid.store.on({scope:this,&load:function(){this.field.focus();}}); &&&&&&&&&} &&&&&}&&&&&&&&&&&&&&&&&&&&&&&&,onKeyUp:function()&{ &&&&&&&&&var&length&=&this.field.getValue().toString(). &&&&&&&&&if(0&===&length&||&this.minChars&&=&length)&{ &&&&&&&&&&&&&this.onTriggerSearch(); &&&&&&&&&} &&&&&}&&&&&&&&&&&&&&&&&&&&&&&,onTriggerClear:function()&{ &&&&&&&&&if&(this.field.getValue())&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&this.field.setValue(''); &&&&&&&&&&&&&this.field.focus();&&&&&&&&&&&& &&&&&&&&&&&&&this.onTriggerSearch(); &&&&&&&&&} &&&&&}&&&&&&&&&&&&&&&&&&&&&&&,onTriggerSearch:function()&{ &&&&&&&&&if(!this.field.isValid())&{ &&&&&&&&&&&&&return; &&&&&&&&&} &&&&&&&&&var&val&=&this.field.getValue(), &&&&&&&&&&&&&store&=&this.grid.store, &&&&&&&&&&&&&proxy&=&store.getProxy(); &&&&&&&&&&&&&&&&&&&if('local'&===&this.mode)&{ &&&&&&&&&&&&&store.clearFilter(); &&&&&&&&&&&&&if(val)&{ &&&&&&&&&&&&&&&&&store.filterBy(function(r)&{ &&&&&&&&&&&&&&&&&&&&&var&retval&=&false; &&&&&&&&&&&&&&&&&&&&&this.menu.items.each(function(item)&{ &&&&&&&&&&&&&&&&&&&&&&&&&if(!item.checked&||&retval)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&return; &&&&&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&var&rv&=&r.get(item.dataIndex); &&&&&&&&&&&&&&&&&&&&&&&&&rv&=&rv&instanceof&Date&?&Ext.Date.format(rv,&this.dateFormat&||&r.fields.get(item.dataIndex).dateFormat)&:& &&&&&&&&&&&&&&&&&&&&&&&&&var&re&=&new&RegExp(val,&'gi'); &&&&&&&&&&&&&&&&&&&&&&&&&retval&=&re.test(rv); &&&&&&&&&&&&&&&&&&&&&},&this); &&&&&&&&&&&&&&&&&&&&&if(retval)&{ &&&&&&&&&&&&&&&&&&&&&&&&&return&true; &&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&return& &&&&&&&&&&&&&&&&&},&this); &&&&&&&&&&&&&} &&&&&&&&&&&&&else&{ &&&&&&&&&&&&&} &&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&&&else&if(proxy&instanceof&Ext.data.proxy.Server)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&if(store.lastOptions&&&&store.lastOptions.params)&{ &&&&&&&&&&&&&&&&&store.lastOptions.params[store.paramNames.start]&=&0; &&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&&&var&fields&=&[]; &&&&&&&&&&&&&this.menu.items.each(function(item)&{ &&&&&&&&&&&&&&&&&if(item.checked&&&&item.dataIndex)&{ &&&&&&&&&&&&&&&&&&&&&fields.push(item.dataIndex); &&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&}); &&&&&&&&&&&&&&&&&&&&&&&&&&&delete(proxy.extraParams[this.paramNames.fields]); &&&&&&&&&&&&&delete(proxy.extraParams[this.paramNames.query]); &&&&&&&&&&&&&if&(store.lastOptions&&&&store.lastOptions.params)&{ &&&&&&&&&&&&&&&&&delete(proxy.lastOptions.params[this.paramNames.fields]); &&&&&&&&&&&&&&&&&delete(proxy.lastOptions.params[this.paramNames.query]); &&&&&&&&&&&&&} &&&&&&&&&&&&&if(fields.length)&{ &&&&&&&&&&&&&&&&&proxy.extraParams[this.paramNames.fields]&=&(fields); &&&&&&&&&&&&&&&&&proxy.extraParams[this.paramNames.query]&=&(val); &&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&&&store.load(); &&&&&&&&&} &&&&&&}&&&&&&&&&&&&&&&&&&&&&&&,setDisabled:function()&{ &&&&&&&&&this.field.setDisabled.apply(this.field,&arguments); &&&&&}&&&&&&&&&&&&&&&&&&&&&&&,enable:function()&{ &&&&&&&&&this.setDisabled(false); &&&&&}&&&&&&&&&&&&&&&&&&&&&&&,disable:function()&{ &&&&&&&&&this.setDisabled(true); &&&&&}&&&&&&&&&&&&&&&&&&&&&&&,reconfigure:function()&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&var&menu&=&this. &&&&&&&&&menu.removeAll(); &&&&&&&&&&&&&&&&&&&if(this.showSelectAll&&&&'radio'&!==&this.menuStyle)&{ &&&&&&&&&&&&&menu.add({ &&&&&&&&&&&&&&&&&xtype:&'menucheckitem', &&&&&&&&&&&&&&&&&text:this.selectAllText, &&&&&&&&&&&&&&&&&checked:!(this.checkIndexes&instanceof&Array), &&&&&&&&&&&&&&&&&hideOnClick:false, &&&&&&&&&&&&&&&&&handler:function(item)&{ &&&&&&&&&&&&&&&&&&&&&var&checked&=&item. &&&&&&&&&&&&&&&&&&&&&item.parentMenu.items.each(function(i)&{ &&&&&&&&&&&&&&&&&&&&&&&&&if(item&!==&i&&&&i.setChecked&&&&!i.disabled)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&i.setChecked(checked); &&&&&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&}); &&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&},'-'); &&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&var&columns&=&this.grid.headerCt.items. &&&&&&&&&var&group&=& &&&&&&&&&if('radio'&===&this.menuStyle)&{ &&&&&&&&&&&&&group&=&'g'&+&(new&Date).getTime();&&&& &&&&&&&&&} &&&&&&&&& &&&&&&&&&Ext.each(columns,&function(column)&{ &&&&&&&&&&&&&var&disable&=&false; &&&&&&&&&&&&&if(column.text&&&&column.dataIndex&&&&column.dataIndex&!=&'')&{ &&&&&&&&&&&&&&&&&Ext.each(this.disableIndexes,&function(item)&{ &&&&&&&&&&&&&&&&&&&&&disable&=&disable&?&disable&:&item&===&column.dataI &&&&&&&&&&&&&&&&&}); &&&&&&&&&&&&&&&&&if(!disable)&{ &&&&&&&&&&&&&&&&&&&&&menu.add({ &&&&&&&&&&&&&&&&&&&&&&&&&xtype:&'menucheckitem', &&&&&&&&&&&&&&&&&&&&&&&&&text:&column.text, &&&&&&&&&&&&&&&&&&&&&&&&&hideOnClick:&false, &&&&&&&&&&&&&&&&&&&&&&&&&group:group, &&&&&&&&&&&&&&&&&&&&&&&&&checked:&'all'&===&this.checkIndexes, &&&&&&&&&&&&&&&&&&&&&&&&&dataIndex:&column.dataIndex, &&&&&&&&&&&&&&&&&&&&&}); &&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&} &&&&&&&&&},&this); &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(this.checkIndexes&instanceof&Array)&{ &&&&&&&&&&&&&Ext.each(this.checkIndexes,&function(di)&{ &&&&&&&&&&&&&&&&&var&item&=&menu.items.findBy(function(itm)&{ &&&&&&&&&&&&&&&&&&&&&return&itm.dataIndex&===& &&&&&&&&&&&&&&&&&}); &&&&&&&&&&&&&&&&&if(item)&{ &&&&&&&&&&&&&&&&&&&&&item.setChecked(true,&true); &&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&},&this); &&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(this.readonlyIndexes&instanceof&Array)&{ &&&&&&&&&&&&&Ext.each(this.readonlyIndexes,&function(di)&{ &&&&&&&&&&&&&&&&&var&item&=&menu.items.findBy(function(itm)&{ &&&&&&&&&&&&&&&&&&&&&return&itm.dataIndex&===& &&&&&&&&&&&&&&&&&}); &&&&&&&&&&&&&&&&&if(item)&{ &&&&&&&&&&&&&&&&&&&&&item.disable(); &&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&},&this); &&&&&&&&&} &&&&&&&&&&&&&&&}&&&&&&&&});&&&&
本文地址 :
------分隔线----------------------------1398人阅读
EXTJS(3)
JAVASCRIPT编程(18)
大规模客户端应用通常不好实现不好组织也不好维护,因为功能和人力的不断增加,这些应用的规模很快就会超出掌控能力,ExtJS 4 带来了一个新的应用架构,不但可以组织代码,还可以减少实现的内容
新的应用架构遵照一个类MVC的模式,模型(Models)和控制器(Controllers)首次被引入。业界有很多种MVC架构,基本大同小异,ExtJS 4的定义如下:
Model模型&是字段和它们的数据的集合,例如User模型带有username和password字段,模型知道如何持久化自己的数据,并且可以和其他模型关联,模型跟ExtJS
3 中的Record类有点像(区别是,Record只是单纯的扁平结构,而Model可以nest),通常都用在Store中去展示grid和其他组件的数据
View视图&是组件的一种,专注于界面展示 – grid, tree, panel 都是view
Controllers控制器&一个安放所有使你的app正确工作的代码的位置,具体一点应该是所有动作,例如如何渲染view,如何初始化model,和app的其他逻辑
这篇教程中将创建一个简单的管理用户数据的例子,做完这个例子,你会学会如何用ExtJS 4的架构把简单的应用组织到一起。
应用架构是关于提供结构和一致性,是关于真实的类和框架代码的,遵守约定可以带来很多重要的好处:
每个应用都是相同的工作方式,所以你只需要学习一次
可以很容易的共享代码,因为所有应用工作模式都一样
可以创建属于自己的混淆的版本用于发布
File Structure文件结构
ExtJS 4 应用都遵循一个统一的目录结构,每个应有都相同。详情可以参见,MVC中,所有类都放在app目录里面,这个目录可以有子目录,代表的是命名空间(一个子目录对应一个命名空间),使用不同的目录存放views,models,controllers,stores,当我们完成例子的时候,目录结构应该和下面截图一样:
在这个例子中所有文件都在'account_manager'目录中,ExtJS SDK必须的文件在目录ext-4.0中,因此,index.html应该如下:
&title&Account Manager&/title&
&link rel=&stylesheet& type=&text/css& href=&ext-4.0/resources/css/ext-all.css&&
&script type=&text/javascript& src=&ext-4.0/ext-debug.js&&&/script&
&script type=&text/javascript& src=&app.js&&&/script&
&body&&/body&
Creating the application in app.js 在app.js中创建应用
每个ExtJS 4的应用都从一个Application类的实例开始,这个实例包含应用的全局配置(例如应用的名字),这个实例也负责维护对全部模型、视图、控制器的引用的维护,还有一个launch函数,会在所有加载项加载完成之后调用。
让我们创建一个简单的Account Manager应用管理用户帐户。首先需要选择一个全局命名空间,所有ExtJS4应用都需要有一个全局命名空间,以让所有应用中的类安放到其中,这个例子中我们使用AM(Account Manager)
Ext.application({
//今天有人问我,demo运行出错,
//他妹的,官方demo错了 官方demo写的是 requires: 'Ext.container.Viewport',
//这里的requires需要是个数组,extjs源码没处理好只有一个requires的情况
requires: ['Ext.container.Viewport'],
name: 'AM',
appFolder: 'app',
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'fit',
xtype: 'panel',
title: 'Users',
html : 'List of users will go here'
首先我们调用了Ext.application创建了一个应用实例,并设置了应用名称”AM”,这样做会自动创建一个全局变量”AM”,并自动注册命名空间”AM”到Ext.Loader,用类似的方式也设置了app作为appFolder。另外在launch函数中,创建了一个Viewport,只包含一个撑满浏览器窗口的Panel。
Defining a Controller 定义一个控制器
控制器是应用的粘合剂,它们所作的事情就是监听事件并执行动作,继续我们的Account Manager应用,创建一个控制器。创建app/controller/Users.js这个文件,并添加如下代码:
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
init: function() {
console.log('Initialized Users! This happens before the Application launch function is called');
接下来在app.js中添加对Users控制器的引用:
Ext.application({
controllers: [
当我们通过index.html查看应用,Users控制器会被自动加载(因为在app.js的Application中增加了引用),并且Users的init方法会在launch之前调用
init方法是个极好的地方,可以用来设置如何和view交互,通常都使用Controller的一个方法control,control方法使得监听view的事件变的容易,更新一下控制器,让它告知我们panel何时渲染:
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'viewport & panel': {
render: this.onPanelRendered
onPanelRendered: function() {
console.log('The panel was rendered');
我们已经更新了init方法,使用this.controll给视图设置监听器。这个controll方法,使用最新的组件查询引擎(ComponentQuery)可以快速方便的找到页面上的组件。如果你对ComponentQuery不熟悉,可以查看ComponentQuery文档进行详细了解。简要一点,ComponentQuery可以允许我们使用一个类似css选择器的方式找到组件。
在例子的init方法中我们应用了'viewport
& panel',可以解释为“查找Viewport直接后代中的所有Panel组件”,然后我们提供了一个对象匹配事件名称(这个例子中只用了render)来提供响应函数。全部的影响就是无论哪个组件符合我们的选择器,当它的render事件触发时,我们的onPanelRendered函数都会被调用。
当我们运行应用程序,可以看到如下图所示:
这不是最激动人心的应用,但是它展示给我们,开始一段有组织的代码是多么容易。让我们增加一点内容,加一个grid。
Defining a View 定义一个视图
直到现在,我们的应用只有很少代码,只有两个文件app.js和app/controller/Users.js,现在我们想增加一个grid显示所有系统中的用户,是时候更好的组织一下逻辑并开始使用视图了。
视图也是组件,通常都是ExtJS现有组件的子类,现在准备创建用户表,先创建app/view/user/List.js,添加代码:
Ext.define('AM.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.userlist',
title : 'All Users',
initComponent: function() {
this.store = {
fields: ['name', 'email'],
{name: 'Ed',
email: ''},
{name: 'Tommy', email: ''}
this.columns = [
{header: 'Name',
dataIndex: 'name',
{header: 'Email', dataIndex: 'email', flex: 1}
this.callParent(arguments);
我们的视图类就是一个普通的类,这个例子中我们扩展了Grid组件,并设置了别名,这样我们可以用xtype的方式调用这个组件,另外我们也添加了store和columns的配置。
接下来我们需要添加这个视图到Users控制器。因为我们用'widget.'设置了别名,所以我们可以使用userlist作为xtype,就像我们使用之前使用的'panel'。
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
'user.List'
onPanelRendered: ...
接下来修改app.js让视图在viewport中渲染,需要修改launch方法
Ext.application({
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'fit',
xtype: 'userlist'
唯一需要注意的是我们在views数组中指定了'user.List',这告诉应用去自动加载对应的文件,ExtJS4
的动态加载系统会根据规则从服务器自动拉取文件,例如user.List就是规则,把.替换成/就是文件存放路径。刷新一下页面:
Controlling the grid 对列表的控制
注意onPanelRendered方法依然被调用,因为我们的grid依然满足'viewport
& panel'选择器,因为我们的视图继承自Grid,从而继承自Panel
现在我们需要收紧一下选择器,我们使用xtype作为选择器替换之前的'viewport & panel',监听双击事件,以便继续做编辑用户信息:
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
'user.List'
init: function() {
this.control({
'userlist': {
itemdblclick: this.editUser
editUser: function(grid, record) {
console.log('Double clicked on ' + record.get('name'));
注意我们更换了组件查询选择器为'userlist',监听的事件更改为'itemdblclick',响应函数设置为'editUser',现在只是简单的日志出双击行的name属性:
可以看到日志是正确的,但我们实际想做的是编辑用户信息,让我们现在做,创建一个新的视图app/view/user/Edit.js
Ext.define('AM.view.user.Edit', {
extend: 'Ext.window.Window',
alias : 'widget.useredit',
title : 'Edit User',
layout: 'fit',
autoShow: true,
initComponent: function() {
this.items = [
xtype: 'form',
xtype: 'textfield',
name : 'name',
fieldLabel: 'Name'
xtype: 'textfield',
name : 'email',
fieldLabel: 'Email'
this.buttons = [
text: 'Save',
action: 'save'
text: 'Cancel',
scope: this,
handler: this.close
this.callParent(arguments);
这回我们还是继承自一个现存的类Ext.window.Window,还是使用的initComponent方法去指定复杂的items和buttons对象,我们使用了一个'fit'布局和一个表单,表单包括了要编辑的用户信息字段,最后我们创建了两个按钮,一个用来关闭窗口,另一个用来保存变更。
现在我们要做的就是在控制器加载这个视图,渲染并且加载用户信息:
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
'user.List',
'user.Edit'
editUser: function(grid, record) {
var view = Ext.widget('useredit');
view.down('form').loadRecord(record);
首先我们用Ext.widget方法创建了视图,这个方法等同于Ext.create('widget.useredit'),然后我们又一次借助组件查询找到了窗口中的表单,每个ExtJS4中的组件都有一个down方法,可以借助组件查询支持的选择器来迅速找到任意下层的组件。
双击表格中的一行可以看到:
Creating a Model and a Store
现在我们有了表单,可以开始编辑和保存用户信息了,但是这之前需要做一点点重构。
AM.view.user.List创建了一个内联的Store,这样可以工作但是我们需要把Store分离出来以便我们在应用的其他位置可以引用并更新其中的信息,我们把它放在它应该在的文件中app/store/Users.js:
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
fields: ['name', 'email'],
{name: 'Ed',
email: ''},
{name: 'Tommy', email: ''}
现在我们需要做两处变更,首先我们需要让Users初始化的时候加载这个Store:
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
然后我们要把之前直接在视图中内联的store更改掉,app/view/user/List.js,改成用id引用store
Ext.define('AM.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.userlist',
//we no longer define the Users store in the `initComponent` method
store: 'Users',
控制器的代码中中引入了store,store会被自动加载到页面并赋予一个storeId,这让视图中使用store变的容易(这个例子中,只要配置store:
'Users'就可以了)
现在我们只是在store中内联的定义了两个字段 (‘name’ 和 ‘email’),这样可以工作,但是ExtJS4中有一个强大的Ext.data.Model类,在编辑用户的时候我们可以借助它,使用Model重构一下Store,在app/model/User.js中创建一个Model:
Ext.define('AM.model.User', {
extend: 'Ext.data.Model',
fields: ['name', 'email']
这就是定义我们的Model需要做的,现在需要让Store引用Model替换掉使用内联字段的方式,并且让控制器也引用Model:
//the Users controller will make sure that the User model is included on the page and available to our app
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
stores: ['Users'],
models: ['User'],
// we now reference the Model instead of defining fields inline
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
{name: 'Ed',
email: ''},
{name: 'Tommy', email: ''}
我们的重构可以让接下来的工作简单一下,但是不会影响现有功能,我们刷新一下页面,检查一下是否正常工作:
Saving data with the Model 利用模型保存数据
现在我们有了一个用户数据表,双击每一行都能打开一个编辑窗口,现在要做的是保存编辑变更,编辑窗口有一个编辑表单,还有保存按钮,现在我们更新一下控制器让保存按钮有响应:
Ext.define('AM.controller.Users', {
init: function() {
this.control({
'viewport & userlist': {
itemdblclick: this.editUser
'useredit button[action=save]': {
click: this.updateUser
updateUser: function(button) {
console.log('clicked the Save button');
我们在this.control方法中增加了一个组件查询选择器'useredit
button[action=save]',这里说明一下,这个选择器和第一个工作方式相同,注意我们定义保存按钮的时候增加了一个配置{action:
'save'},这个选择器的意思就是选择xytpe是useredit的组件下的所有action属性是save的按钮
检查一下updateUser是不是被调用了:
上图说明工作正常,接下来填充updateUser真正的逻辑。我们需要把数据从表单中取出,再设置回store中:
updateUser: function(button) {
= button.up('window'),
= win.down('form'),
record = form.getRecord(),
values = form.getValues();
record.set(values);
win.close();
让我们分解一下这里都做了什么。我们的响应函数接收到按钮的引用,但是我们关心的是表单和窗口,通过按钮和组件查询,可以找到关心的东西,这里首先用了button.up('window')找到了窗口,然后用win.down('form')找到了表单。
这之后我们取出表单关联的record并用表单中的输入值更新了record,最后关闭了窗口关注回到表格上,我们把用户名更改为'Ed
Spencer'点击保存应该可以看到:
Saving to the server 保存到服务器
很简单吧。让我们增加和服务器端的交互完成这个例子。现在我们还是应编码了两行表格的数据,现在让我们通过ajax加载:
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
type: 'ajax',
url: 'data/users.json',
type: 'json',
root: 'users',
successProperty: 'success'
这里我们去除了'data'属性,替换成proxy,代理是让Store或者Model加载和保存数据的一个方式,有AJAX,JSONP,HTML5的localStorage本地存储等。这里我们使用了一个简单的AJAX代理,让它通过URL&'data/users.json'加载数据。
我们同时给代理附加了一个reader,reader是用来把服务器返回的数据解码成Store能理解的格式,这次我们使用了JSON reader,并且指定了root和successProperty配置(JSON
reader的详细配置看文档),最后我们创建一下数据文件data/users.json,输入内容:
success: true,
{id: 1, name: 'Ed',
email: ''},
{id: 2, name: 'Tommy', email: ''}
其他的变更就是我们给Store设置了autoLoad属性并设置为true,这意味着Store生成之后会自动让Proxy加载数据,刷新一下页面应该是看到和之前同样的结果,不同的是现在不是在程序中应编码数据了
最后的事情是将变更传回服务器端,这个例子中我们使用静态的JSON文件,没有使用数据库,但足够说明我们例子的了,首先做一点点变化告知proxy用于更新的url:
type: 'ajax',
read: 'data/users.json',
update: 'data/updateUsers.json'
type: 'json',
root: 'users',
successProperty: 'success'
依然从users.json读取数据,但是变更会发送到updateUsers.json,这里我们做一个模拟的应答回包以让我们知道程序可以正确工作,updateUsers.json只需要包含{&success&:
true},其他要做的就是让Store在编辑之后进行同步,需要在updateUser函数中增加一行代码:
updateUser: function(button) {
= button.up('window'),
= win.down('form'),
record = form.getRecord(),
values = form.getValues();
record.set(values);
win.close();
this.getUsersStore().sync();
现在我们可以运行一下整个例子,检查是不是每个功能都正常,编辑表格中的一行,看看能不能正确的把请求发送给updateUser.json
Deployment 发布
新出台的Sencha SDK Tools&&让ExtJS4的应用发布变的轻松。这个工具可以让你生成依赖清单,并生成一个最小化版本
详细介绍可以查看&
Next Steps 下一步
这里我们创建了一个非常简单的例子,但是基本功能都囊括了,你可以开始举一反三开发其他功能了,记得遵守开发模式,代码组织方式,以上代码的例子在Ext JS 4 SDK中,examples/app/simple目录中
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1071838次
积分:11046
积分:11046
排名:第1157名
原创:78篇
转载:350篇
评论:79条
(2)(3)(2)(1)(3)(1)(4)(2)(2)(6)(25)(2)(5)(3)(65)(20)(2)(4)(4)(58)(12)(10)(82)(75)(25)(1)(1)(1)(3)(2)(8)(1)

我要回帖

更多关于 extjs 操作数组 的文章

 

随机推荐