首页 > 代码库 > 当GridPanel添加新的条目的时候,第一个可编辑Cell自动Focus

当GridPanel添加新的条目的时候,第一个可编辑Cell自动Focus


Ext版本:4.2

需求描述:

系统中有大量的可编辑列表,用户可以动态的添加条目。每当添加条目的时候,新添加的条目的第一个可编辑单元格,自动获取焦点。如下图所示:

wKiom1RZi4LgPcJaAAFWgZUmASc303.jpg

第一思路,就是监听GridPanel的add事件,一旦Grid添加条目就触发Focus事件。查看API发现,Grid根本就没有监听Store内容变化的事件。大多数是监听Grid包含组件的事件和view的事件。如下图:

wKioL1RZjOazO-W3AAOfvs1_TqU409.jpg


所以,只能转变思路。监听Store的add事件,一旦Store添加条目,则触发Grid的Focus事件。但是,Grid和Store是多对一的关系,所以Grid类中持有Store的引用,但是Store中找不到Grid的引用。所以,不能简单的把对add事件的handler写在Store中。


那么,继续变换思路。既然Grid引用了Store,那么把对Store的监听事件写在Grid的类定义中。如下:

Ext.define("Soims.view.voyage.VoyageTask", {
    extend: ‘Ext.grid.Panel‘,
    alias: ‘widget.voyagetask‘,
    plugins: [{ ptype: ‘cellediting‘, clicksToEdit: 1 }],
    selType: ‘rowmodel‘,
    initComponent: function () {
        this.store = Ext.create(‘Soims.store.voyage.VoyageTask‘); // 关系引用
        this.columns = [
            // 略
            }];
        this.tbar = [{
            text: ‘添加‘,
            xtype: ‘button‘,
            iconCls: ‘Add‘,
            hidden: this.isShow,
            itemId: ‘add‘

        }];
        this.store.on(‘add‘,this.onInsertRecord,this); // 注意:需要把this传递进去
        this.callParent();
    },
    onInsertRecord: function (store, records, index,opt) {
        var editor = this.getCellRowEditor(),
            res;
        console.log(editor);
        console.log(this.getStore().getAt(0));
        console.log(this.columns[0]);
        res = editor.startEdit(this.getStore().getAt(0), this.columns[0]); // focus
        console.log(res);
    }
});

这里有一点需要注意:就是给store的add绑定事件的时候,需要改变this指针。否则,在onIsertRecord()方法中,得不到Grid的引用。


事情还没有结束,因为结果出乎意料。虽然,监听事件执行了,但是Cell并没有Focus,查看输出结果,如下图:

wKioL1RZj-jj4WzpAAFdlkjW1I0066.jpg

也就是说,各个对象都能获取,但是不能正确出发startEdit()事件。


在startEdit()事件上加断点,很清楚的发现,当出发startEdit()的时候,Grid中还没有添加条目,如下图所示:

wKioL1RZk4myqTHaAARdZP8T3kE780.jpg


但是startEdit()事件,是需要当前触发行的context,如果找不到则不能编辑,如下图:

wKioL1RZk5rCwuQKAAFMJzFc88k769.jpg


根据原因是,Store类的insert方法中,会触发add事件,从而处理各种监听事件,包括view的onAdd()添加Node,和我们自定义的onIsertRecord()触发焦点。由于先注册的事件后触发(跟浏览器有关吗?),导致我们的处理事件先被调用,导致了这个问题。


Store的insert方法源码:

insert: function(index, records) {
        // 略..
        
            me.fireEvent(‘add‘, me, out, index); // 触发方法
            me.fireEvent(‘datachanged‘, me);
            
        // 略..
    }


view的onAdd()调用顺序为:

BufferedRendererTableView.onAdd() -> Ext.view.Table.onAdd() -> Ext.view.AbstractView.onAdd()


AbstractView.onAdd方法源码:

onAdd : function(store, records, index) {
        // 略..
        
        nodes = me.doAdd(records, index);
        
        // 略..

    }


解决办法:把Focus 处理事件,放到Store.insert();代码之后,这样调用顺序肯定是我们预期的。

        ‘editvoyagetask  button[itemId=add]‘: {
                click: function (button, e) {
                    var model = Ext.create(‘Soims.model.voyage.VoyageTask‘),
                        grid = button.up(‘panel‘),
                        editor;

                    grid.getStore().insert(0, model);

                    editor = grid.getCellRowEditor();
                    editor.startEdit(grid.getStore().getAt(0), grid.columns[0]);
                }
            }


当然,这样的处理是违反了我们开始的初衷的。


思考:


  1. 是否需要给监听事件设置处理顺序?怎样设置?

  2. Grid是否需要监听Store的事件,并公布接口?



本文出自 “技术人生” 博客,请务必保留此出处http://wangyuelucky.blog.51cto.com/1011508/1572211

当GridPanel添加新的条目的时候,第一个可编辑Cell自动Focus