当前位置: 代码迷 >> JavaScript >> ExtJS 4.0 改进Ext.grid.plugin.RowEditing (重构,v1.4版本,2011-09-11)
  详细解决方案

ExtJS 4.0 改进Ext.grid.plugin.RowEditing (重构,v1.4版本,2011-09-11)

热度:951   发布时间:2012-11-04 10:42:41.0
ExtJS 4.0 改善Ext.grid.plugin.RowEditing (重构,v1.4版本,2011-09-11)

Ext4.0 自带的Ext.ux.RowEditing还不够完善,随手写个ux来用下,

?

v1.4 2011-09-12 变更内容:

1.重构,修复不少bug以及合并/新增一些配置项(具体看附件中的文档)

2.支持jsduck生成文档 (https://github.com/senchalabs/jsduck)

?

?

v1.0 2011.04.27 变更内容:
1.增加canceledit事件
2.增加startAdd方法,方便crud表格的添加操作
3.添加点击取消按钮后,自动重置或删除记录的功能

v1.1 2011.05.03 变更内容:
1.startAdd方法增加position参数,修复autoSync设值的bug
2.配置参数removePhantomsOnCancel改名为autoRecoverOnCancel
3.startEdit前先调用cancelEdit函数,以便正确的恢复现场

v1.2 2011.05.04 变更内容:
1.包名改为Ext.ux.grid.plugin
2.添加配置参数hideTooltipOnAdd
3.判断是否删除新增记录的逻辑优化
4.代码风格等方面的改进

?

v1.3 2011.05.22 变更内容:?

1. 设置clicksToEdit为0,可取消双击/单击事件触发编辑

2. 提供field默认配置,只需给column添加一个fieldType?

?

           {
               text: 'Enable',
               dataIndex: 'enable',
               width: 80,
               renderer: function(v){return v?'Enable':'Disable'},
               fieldType: 'checkboxfield',
               field: {
                   boxLabel: 'Enable'
               }
           }
?


代码如下:

?

?

 /**
 * @class Ext.ux.grid.plugin.RowEditing
 * @extends Ext.grid.plugin.RowEditing
 * @xtype ux.rowediting
 * 
 * 对Ext原有的RowEditing插件增加新功能.<br/>
 * Improve Ext.ux.grid.plugin.RowEditing,add some usefull features.<br/>
 * 
 * @author      tz <atian25@qq.com> <br/>
 * @date        2011-08-20  <br/>
 * @version     1.4   <br/>
 * @blog        http://atian25.iteye.com    <br/>
 * @forum       http://www.sencha.com/forum/showthread.php?131482-Ext.ux.RowEditing-add-some-usefull-features<br/>
 *
 */
Ext.define('Ext.ux.grid.plugin.RowEditing', {
    extend: 'Ext.grid.plugin.RowEditing',
    alias: 'plugin.ux.rowediting', 
    
    /**
     * 是否添加记录在当前位置<br/>
     * whether add record at current rowIndex.<br/>
     * see {@link #cfg-addPosition}
     * @cfg {Boolean}
     */
    addInPlace: false,
    
    /**
     * 添加记录的具体位置 <br/>
     * * 当addInPlace为true时,该参数<=0代表当前位置之前,否则代表当前位置之后<br/>
     * * 当addInPlace为false时,代表具体的rowIndex,-1则为最后<br/>
     * Special rowIndex of added record.<br/>
     * * when {@link #cfg-addInPlace} is true, this cfg means before(<=0) or after(>0) current rowIndex.<br/>
     * * when {@link #cfg-addInPlace} is false, this cfg means the exact rowIndex.-1 means at the end.
     * @cfg {Number}
     */
    addPosition: 0,
    
    /**
     * 是否点击触发事件,0代表不触发,1代表单击,2代表双击,默认为双击.<br/>
     * The number of clicks on a grid required to display the editor (disable:0,click:1,dblclick:2)
     * @cfg {Number}
     */
    clicksToEdit:2,
    
    /**
     * 是否在取消编辑的时候自动删除添加的记录
     * if true, auto remove phantom record on cancel,default is true.
     * @cfg {Boolean}
     */
    autoRecoverOnCancel: true,
    
    /**
     * adding flag
     * @private
     * @type Boolean
     */
    adding: false,
    
    autoCancel:true,
    
    /**
     * when add record, hide error tooltip for the first time
     * @private
     * @type Boolean
     */
    hideTooltipOnAdd: true,
    
    /**
     * register canceledit event && relay canceledit event to grid
     * @param {Ext.grid.Panel} grid
     * @override
     * @private
     */
    init:function(grid){
        var me = this;
        /**
         * 取消编辑事件.<br/>
         * Fires canceledit event.And will be relayEvents to Grid.<br/>
         * @see {@link Ext.ux.grid.RowActions#event-beforeaction} <br/>
         * @event canceledit
         * @param {Object} context
         */
        me.addEvents('canceledit');
        me.callParent(arguments);
        grid.addEvents('canceledit');
        grid.relayEvents(me, ['canceledit']);
    },
    
    /**
     * 提供默认的Editor配置
     *      @example
     *      {header:'手机',dataIndex:'phone',fieldType:'numberfield',field:{allowBlank:true}}
     * provide default field config
     * @param {String} fieldType 可选值:numberfield,checkboxfield,passwordField
     * @return {Object} 
     * @protected
     */
    getFieldCfg: function(fieldType){
        switch(fieldType){
            case 'passwordField':
                return {
                    xtype: 'textfield',
                    inputType: 'password',
                    allowBlank:false
                }
            case 'numberfield':
                return {
                    xtype: 'numberfield',
		            hideTrigger: true,
		            keyNavEnabled: false,
		            mouseWheelEnabled: false,
		            allowBlank:false
		        }
                
	        case 'checkboxfield':
	            return {
	                xtype: 'checkboxfield',
	                inputValue: 'true',
	                uncheckedValue: 'false'
	            }
	        }
    },
    
    /**
     * Help to config field,just giving a fieldType and field as additional cfg.
     * see {@link #getFieldCfg}
     * @private
     * @override
     */
    getEditor: function() {
        var me = this;

        if (!me.editor) {
            Ext.each(me.grid.headerCt.getGridColumns(),function(item,index,allItems){
                if(item.fieldType){
                    item.field = Ext.applyIf(item.field||{},this.getFieldCfg(item.fieldType))
                }
            },this)
            // keep a reference for custom editor..
            me.editor = me.initEditor();
        }
        me.editor.editingPlugin = me
        return me.editor;
    },
    
    /**
     * if clicksToEdit===0 then mun the click/dblclick event
     * @private
     * @override
     */
    initEditTriggers: function(){
        var me = this 
        var clickEvent = me.clicksToEdit === 1 ? 'click' : 'dblclick'
        me.callParent(arguments); 
        if(me.clicksToEdit === 0){
            me.mun(me.view, 'cell' + clickEvent, me.startEditByClick, me); 
        }
    },
    
    /**
     * 添加记录
     * add a record and start edit it (will not sync store)
     * @param {Model/Object} data Data to initialize the Model's fields with <br/>
     * @param {Object} config see {@link #cfg-addPosition}. 
     */
    startAdd: function(data,config){
        var me = this;
        var cfg = Ext.apply({
            addInPlace: this.addInPlace,
            addPosition: this.addPosition,
            colIndex: 0
        },config)
        
        //find the position
        var position;
        if(cfg.addInPlace){
            var selected = me.grid.getSelectionModel().getSelection()
            if(selected && selected.length>0){
                position = me.grid.store.indexOf(selected[0]) 
                console.log('a',position)
                position += (cfg.addPosition<=0) ? 0: 1
            }else{
                position = 0
            }
        }else{
        	position = (cfg.addPosition==-1 ? me.grid.store.getCount() : cfg.addPosition) || 0
        }
        
        var record = data.isModel ? data : me.grid.store.model.create(data);
        var autoSync = me.grid.store.autoSync;
        me.grid.store.autoSync = false;
        me.grid.store.insert(position, record);
        me.grid.store.autoSync = autoSync;
        
        me.adding = true
        me.startEdit(position,cfg.colIndex);
        
        //since autoCancel:true dont work for me
        if(me.hideTooltipOnAdd && me.getEditor().hideToolTip){
            me.getEditor().hideToolTip()
        }
    },
    
    /**
     * 编辑之前,自动取消编辑
     * Modify: if is editing, cancel first.
     * @private
     * @override
     */
    startEdit: function(record, columnHeader) {
        var me = this;
        if(me.editing){
            me.cancelEdit(); 
        }
        me.callParent(arguments);
    },
    
    /**
     * 修改adding的状态值
     * Modify: set adding=false
     * @private
     * @override
     */
    completeEdit: function() {
        var me = this;
        if (me.editing && me.validateEdit()) {
            me.editing = false;
            me.fireEvent('edit', me.context);
        }
        me.adding = false
    },
    
    /**
     * 取消编辑
     * 1.fireEvent 'canceledit'
     * 2.when autoRecoverOnCancel is true, if record is phantom then remove it
     * @private
     * @override
     */
    cancelEdit: function(){
        var me = this;
        if (me.editing) {
            me.getEditor().cancelEdit();
            me.editing = false;
            me.fireEvent('canceledit', me.context); 
            if (me.autoRecoverOnCancel){
                if(me.adding){
                    me.context.record.store.remove(me.context.record);
                    me.adding = false
                }else{
                    //不需要reject,因为Editor没有更改record.
                    //me.context.record.reject()
                }
            }
        }
    }
})

//ext-lang-zh_CN
if (Ext.grid.RowEditor) {
    Ext.apply(Ext.grid.RowEditor.prototype, {
        saveBtnText: '保存',
        cancelBtnText: '取消',
        errorsText: '错误信息',
        dirtyText: '已修改,你需要提交或取消变更'
    });
}
?

?

?

?

?

8 楼 noto 2011-05-22  
关于UPDATE,CTEATE启用机制到底如何?
是不是要看STORE是否LOAD?


另外,我看了你发在http://www.sencha.com/forum/showthread.php?131482-Ext.ux.grid.plugin.RowEditing-add-some-usefull-features 的帖子。

4.0.1 RowEditing 有BUG,点击要编辑的列,出现了
me["onBeforeItem" + map[newType]] is not a function
而4.0不会。

另外,如果编辑列前放了隐藏的列,则连隐藏列都出现了。

E文不好,不好意思发到/www.sencha.com
9 楼 atian25 2011-05-23  
那2个问题我在4.0.1发布的那天就在论坛提了.
onBeforeItem这个官方已经在跟进了.
隐藏列的那个我提了,被无视了.
RowEditing的问题多的是...

你那问题,我怀疑是store的配置问题. 你试着:
1.把store设为是autoSync
2.通过一个按钮事件,把store的第2条数据修改个值.
3.观察firebug提交的数据.

update/create的判断机制应该是在data/proxy/Rest里面,可以看下源码


ps: 顶楼更新1.3版本
10 楼 noto 2011-05-23  
我找到原因咯,是因为 field 没有名为 “id”的列,另外,在grid也必须定义该列(我只好故意弄个隐藏的列了)
看了 Ext.grid.RowEditor ,有句,应该是这原因。

        me.columns.getKey = function(columnHeader) {
            var f;
            if (columnHeader.getEditor) {
                f = columnHeader.getEditor();
                if (f) {
                    return f.id;
                }
            }
            return columnHeader.id;
        };


我不知道应该怎么修改。
另外,我就是定义了 idProperty ,也没用

在其update 按钮激发了
    completeEdit: function() {
        var me = this,
            form = me.getForm();

        if (!form.isValid()) {
            return;
        }

        form.updateRecord(me.context.record);
        me.hide();
        return true;
    },



结果我在 Ext.form.Basic 找到了 updateRecord 方法

    updateRecord: function(record) {
        var fields = record.fields,
            values = this.getFieldValues(),
            name,
            obj = {};

        fields.each(function(f) {
            name = f.name;
            if (name in values) {
                obj[name] = values[name];
            }
        });

        record.beginEdit();
        record.set(obj);
        record.endEdit();

        return this;
    },


11 楼 noto 2011-05-23  
另外,关于 create ,update,destroy 只像后台发送JSON 串,后台怎么能知道执行哪个啊?
12 楼 atian25 2011-05-23  
Model有个field叫id应该就ok了, Model默认的idProperty就是id
如果你是REST的proxy,那根据GET/POST/PUT/DELETE的方法不同,后台自然知道.
具体看INFOQ的一片关于REST的文章介绍.

通过firebug你可以观察到ajax请求的参数,以及它的method(POST/PUT/DEL/GET)
13 楼 noto 2011-05-23  
但我是用ajax发送的。

另外,又发现,其实不需要ID列,只要后台传来带有 id 的列就可以了,不管model配置是否有id列。

还有,我还是弄不明白 load方法,store原来带条件过去了,想重载最后一次的条件,没reload, 用load不能。

干脆问题一起问

我有个form 和 rowedit 要一起发送到后台,不知道如何做?
因为要一起发送,所以autoSync: true 就不能设了。要用按钮做 sync()
14 楼 atian25 2011-05-24  
1.设置下store.proxy.extraParams (类似以前的store.baseParams),再load
2.那段的源码我没细看,不过应该是根据model的phantom属性来判断是否为新增.
这里有几个需要注意的地方:
1)点击保存的时候,通过firebug观察你的ajax请求是update还是create,并观察对应的参数里面是否有id.
2)后台处理后,必须返回数据{success:true,data:{id:1,xxxx},msg:''}, RowEditing会根据返回值,去更新对应的model (所以如果你没有返回对应的id,它会在grid里面显示新的一行,而你store.load一次后,会发现那一行没了.)

3.既然你是要一起发送的,那form里面的数据可以不在store里面,自然不能autoSync:true,自己调用sync咯.
15 楼 elvishehai 2011-06-14  
想动态的生成ColumnModel怎么搞了,我在gridPanel中使用是OK的,var scm =new Ext.grid.ColumnModel(eval('([' + columnModelStr + '])')); 可是结果是出错了,在rowEditor中grid.getColumnModel().on('hiddenchange', this.verifyLayout, this, {delay:1});这行出错了,就是grid.getColumnModel()为空
16 楼 atian25 2011-09-12  
v1.4 2011-09-12 变更内容:
1.重构,修复不少bug以及合并/新增一些配置项(具体看附件中的文档)
2.支持jsduck生成文档 (https://github.com/senchalabs/jsduck)
17 楼 cpoysy 2012-03-12  
楼主你好,你写的插件有个BUG,当grid里面的数据列数产生横向滚动条的时候则数据向右边拖不动了,
18 楼 cpoysy 2012-03-12  
cpoysy 写道
楼主你好,你写的插件有个BUG,当grid里面的数据列数产生横向滚动条的时候则数据向右边拖不动了,

不好意思,是版本问题,我从4.02换成4.07版本后就没有问题了,谢谢。4.02版本官方的demo如果反复拖动都有问题。
19 楼 atian25 2012-03-12  
cpoysy 写道
楼主你好,你写的插件有个BUG,当grid里面的数据列数产生横向滚动条的时候则数据向右边拖不动了,


横向滚动条是4.1新出的特性吧? 最近都没有时间碰ext.
你看下原版的RowEditor是否会有问题.
我没有改变布局,要不是RowEditor的逻辑改了,要不就是原版就有问题.
20 楼 l_zh_y 2012-04-16  
楼主,请教一下为什么我下下来功能都没表现出来呢?我的代码:
var rowEditing = Ext.create('Ext.ux.grid.plugin.RowEditing',{
clicksToMoveEditor:1,
autoCancel:true,
hideTooltipOnAdd: true
});,求教!
21 楼 atian25 2012-04-16  
l_zh_y 写道
楼主,请教一下为什么我下下来功能都没表现出来呢?我的代码:
var rowEditing = Ext.create('Ext.ux.grid.plugin.RowEditing',{
clicksToMoveEditor:1,
autoCancel:true,
hideTooltipOnAdd: true
});,求教!


firebug有什么报错?
另外检查下插件有否正确加载
22 楼 l_zh_y 2012-04-16  
thank you楼主,原因找到了,是我调用了start方法,而不是你的startAdd方法。还有个问题请教一下,我的第一列是复选框,如果我点击添加时弹出的rowedit中每列输入框的位置就跟我的表头的列对应不上,求教!
23 楼 l_zh_y 2012-04-16  
rowedit和列对不齐的问题解决了,谢谢,具体解决方法大家可以参考这个:http://kldn.iteye.com/blog/1402833
24 楼 wilsonchen 2012-04-26  
现在我有个问题:每次当我点击新增按钮,就会触发update ajax action到后台。
我想通过用户自己点击保存按钮时才触发后台,而不是每一次点击新增就马上触发后台,这个问题应该怎样解决,谢谢。
25 楼 atian25 2012-04-26  
wilsonchen 写道
现在我有个问题:每次当我点击新增按钮,就会触发update ajax action到后台。
我想通过用户自己点击保存按钮时才触发后台,而不是每一次点击新增就马上触发后台,这个问题应该怎样解决,谢谢。


ext自带示例就有, 很久没碰ext了, 好像store.autoSync这个属性
26 楼 wilsonchen 2012-04-26  
atian25 写道
wilsonchen 写道
现在我有个问题:每次当我点击新增按钮,就会触发update ajax action到后台。
我想通过用户自己点击保存按钮时才触发后台,而不是每一次点击新增就马上触发后台,这个问题应该怎样解决,谢谢。


ext自带示例就有, 很久没碰ext了, 好像store.autoSync这个属性


为何clicksToMoveEditor:1没有起到任何作用,双击编辑出来后,点击下一行,不能进行编辑,只能够按了cancel按钮才能再双击下一行,为何呢?谢谢
27 楼 atian25 2012-04-26  
wilsonchen 写道
atian25 写道
wilsonchen 写道
现在我有个问题:每次当我点击新增按钮,就会触发update ajax action到后台。
我想通过用户自己点击保存按钮时才触发后台,而不是每一次点击新增就马上触发后台,这个问题应该怎样解决,谢谢。


ext自带示例就有, 很久没碰ext了, 好像store.autoSync这个属性


为何clicksToMoveEditor:1没有起到任何作用,双击编辑出来后,点击下一行,不能进行编辑,只能够按了cancel按钮才能再双击下一行,为何呢?谢谢



clicksToEdit被我改了,你看下自带的源码吧,也许是这个原因.
  相关解决方案