• Extjs4.2 Grid搜索Ext.ux.grid.feature.Searching的使用


    背景

    Extjs4.2 默认提供的Search搜索,功能还是非常强大的,只是对于国内的用户来说,还是不习惯在每列里面单击好几下再筛选,于是相当当初2.2里面的搜索,更加的实用点,于是在4.2里面实现。

    国际惯例,先上图

    参考文献

    https://gist.github.com/aghuddleston/3297619/

    http://gridsearch.extjs.eu/

    国外的大牛已经帮我们实现了在4.0中的应用,但是到4.2还需要做少许变更才可以使用。

    修改后的源代码如下[复制如下代码,放到ux/grid/features/Searching.js]:

    // JavaScript Document// vim: ts=4:sw=4:nu:fdc=4:nospell
    /**
     * Search plugin for Ext.grid.GridPanel, Ext.grid.EditorGrid ver. 2.x or subclasses of them
     *
     * @author    Ing. Jozef Sakalos
     * @copyright (c) 2008, by Ing. Jozef Sakalos
     * @date      17. January 2008
     * @version   $Id: Ext.ux.grid.Search.js 220 2008-04-29 21:46:51Z jozo $
     *
     * @license Ext.ux.grid.Search is licensed under the terms of
     * the Open Source LGPL 3.0 license.  Commercial use is permitted to the extent
     * that the code/component(s) do NOT become part of another Open Source or Commercially
     * licensed development library or toolkit without explicit permission.
     * 
     * License details: http://www.gnu.org/licenses/lgpl.html
     */
    
    /*
        Revised for Ext 4
        by Nathan LeBlanc
        on July 8, 2011
    */
    
    Ext.define('Ext.ux.grid.feature.Searching', {
        extend: 'Ext.grid.feature.Feature',
        alias: 'feature.searching',
    
        /**
         * cfg {Boolean} autoFocus true to try to focus the input field on each store load (defaults to undefined)
         */
    
        /**
         * @cfg {String} searchText Text to display on menu button
         */
        searchText:'查询',
    
        /**
         * @cfg {String} searchTipText Text to display as input tooltip. Set to '' for no tooltip
         */ 
        searchTipText:'输入关键字回车查询',
    
        /**
         * @cfg {String} selectAllText Text to display on menu item that selects all fields
         */
        selectAllText:'所有列',
    
        /**
         * @cfg {String} position Where to display the search controls. Valid values are top and bottom (defaults to bottom)
         * Corresponding toolbar has to exist at least with mimimum configuration tbar:[] for position:top or bbar:[]
         * for position bottom. Plugin does NOT create any toolbar.
         */
        position:'top',
    
        /**
         * @cfg {String} iconCls Icon class for menu button (defaults to icon-magnifier)
         */
        iconCls: 'Zoom',
    
        /**
         * @cfg {String/Array} checkIndexes Which indexes to check by default. Can be either 'all' for all indexes
         * or array of dataIndex names, e.g. ['persFirstName', 'persLastName']
         */
        checkIndexes:'all',
    
        /**
         * @cfg {Array} disableIndexes Array of index names to disable (not show in the menu), e.g. ['persTitle', 'persTitle2']
         */
        disableIndexes:[],
    
        /**
         * @cfg {String} dateFormat how to format date values. If undefined (the default) 
         * date is formatted as configured in colummn model
         */
        dateFormat:undefined,
    
        /**
         * @cfg {Boolean} showSelectAll Select All item is shown in menu if true (defaults to true)
         */
        showSelectAll:true,
    
        /**
         * @cfg {String} menuStyle Valid values are 'checkbox' and 'radio'. If menuStyle is radio
         * then only one field can be searched at a time and selectAll is automatically switched off.
         */
        menuStyle:'checkbox',
    
        /**
         * @cfg {Number} minChars minimum characters to type before the request is made. If undefined (the default)
         * the trigger field shows magnifier icon and you need to click it or press enter for search to start. If it
         * is defined and greater than 0 then maginfier is not shown and search starts after minChars are typed.
         */
        minChars: 2,
        /**
         * @cfg {String} minCharsTipText Tooltip to display if minChars is > 0
         */
        minCharsTipText:'至少输入{0}个字符',
    
        /**
         * @cfg {String} mode Use 'remote' for remote stores or 'local' for local stores. If mode is local
         * no data requests are sent to server the grid's store is filtered instead (defaults to 'remote')
         */
        mode:'remote',
    
        /**
         * @cfg {Array} readonlyIndexes Array of index names to disable (show in menu disabled), e.g. ['persTitle', 'persTitle2']
         */
    
        /**
         * @cfg {Number} width Width of input field in pixels (defaults to 100)
         */
        100,
    
        /**
         * @cfg {Object} paramNames Params name map (defaults to {fields:'fields', query:'query'}
         */
        paramNames: {
             fields:'fields'
            ,query:'query'
        },
    
        /**
         * @cfg {String} shortcutKey Key to fucus the input field (defaults to r = Sea_r_ch). Empty string disables shortcut
         */
        shortcutKey:'r',
    
        /**
         * @cfg {String} shortcutModifier Modifier for shortcutKey. Valid values: alt, ctrl, shift (defaults to alt)
         */
        shortcutModifier:'alt',
    
        /**
         * @cfg {String} align 'left' or 'right' (defaults to 'left')
         */
        align:'left',
        /**
         * @cfg {Number} minLength force user to type this many character before he can make a search
         */
        minLength: 2,
        /**
         * @cfg {Ext.Panel/String} toolbarContainer Panel (or id of the panel) which contains toolbar we want to render
         * search controls to (defaults to this.grid, the grid this plugin is plugged-in into)
         */
                
        //attachEvents: function() {
        //    this.grid = this.view.up('gridpanel');
        //    if(this.grid.rendered)
        //        this.onRender();
        //    else
        //        this.grid.on('render', this.onRender, this);
        //},
        
        init: function (grid) {
            this.grid = grid;
            if (this.grid.rendered)
                this.onRender();
            else
                this.grid.on('render', this.onRender, this);
        },
    
        onRender:function() {
            
            var panel = this.toolbarContainer || this.grid;
            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);
            }
    
            // add menu
            this.menu = Ext.create('Ext.menu.Menu');
    
            // handle position
            if('right' === this.align) {
                tb.add('->');
            }
            else {
                if(0 < tb.items.getCount()) {
                    tb.add('-');
                }
            }
    
            // add menu button
            tb.add({
                 text:this.searchText
                ,menu:this.menu
                ,iconCls:this.iconCls
            });
    
            // add input field (TwinTriggerField in fact)
            this.field = Ext.create('Ext.form.TwinTriggerField', {
                this.width,
                qtip: 'ddd',
                selectOnFocus:undefined === this.selectOnFocus ? true : this.selectOnFocus,
                triggerCls: 'x-form-clear-trigger',
                //triggerCls: this.minChars ? 'x-hidden' : 'x-form-search-trigger',
                onTrigger1Click: Ext.bind(this.onTriggerClear, this),
                //onTrigger2Click: this.minChars ? Ext.emptyFn : Ext.bind(this.onTriggerSearch, this),
                //onTrigger1Click: this.minChars ? Ext.emptyFn : Ext.bind(this.onTriggerSearch, this),
                minLength:this.minLength
            });
            
            // install event handlers on input field
            this.field.on('render', function() {
                
                var qtip = this.minChars ? Ext.String.format(this.minCharsTipText, this.minChars) : this.searchTipText;
                Ext.QuickTips.register({
                    target: this.field.inputEl,
                    text: qtip
                });
                
                if(this.minChars) {
                    this.field.el.on({scope:this, buffer:300, keyup:this.onKeyUp});
                }
    
                // install key map
                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);
    
            // reconfigure
            this.reconfigure();
    
            // keyMap
            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();}});
            }
        } // eo function onRender
        // }}}
        // {{{
        /**
         * field el keypup event handler. Triggers the search
         * @private
         */
        ,onKeyUp:function() {
            var length = this.field.getValue().toString().length;
            if(0 === length || this.minChars <= length) {
                this.onTriggerSearch();
            }
        } // eo function onKeyUp
        // }}}
        // {{{
        /**
         * private Clear Trigger click handler
         */
        ,onTriggerClear:function() {
            if (this.field.getValue()) {
                //if (this.field.getValue().length < this.minChars) {
                //    this.field.setValue('');
                //    return;
                //}
                this.field.setValue('');
                this.field.focus();            
                this.onTriggerSearch();
            }
        } // eo function onTriggerClear
        // }}}
        // {{{
        /**
         * private Search Trigger click handler (executes the search, local or remote)
         */
        ,onTriggerSearch:function() {
            if(!this.field.isValid()) {
                return;
            }
            var val = this.field.getValue(),
                store = this.grid.store,
                proxy = store.getProxy();
    
            // grid's store filter
            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) : rv;
                            var re = new RegExp(val, 'gi');
                            retval = re.test(rv);
                        }, this);
                        if(retval) {
                            return true;
                        }
                        return retval;
                    }, this);
                }
                else {
                }
            }
            // ask server to filter records
            // your proxy must be a Server proxy
            else if(proxy instanceof Ext.data.proxy.Server) {
                // clear start (necessary if we have paging)
                if(store.lastOptions && store.lastOptions.params) {
                    store.lastOptions.params[store.paramNames.start] = 0;
                }
    
                // get fields to search array
                var fields = [];
                this.menu.items.each(function(item) {
                    if(item.checked && item.dataIndex) {
                        fields.push(item.dataIndex);
                    }
                });
    
                // add fields and query to baseParams of store
                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);
                }
    
                // reload store
                store.load();
            }
    
        } // eo function onTriggerSearch
        // }}}
        // {{{
        /**
         * @param {Boolean} true to disable search (TwinTriggerField), false to enable
         */
        ,setDisabled:function() {
            this.field.setDisabled.apply(this.field, arguments);
        } // eo function setDisabled
        // }}}
        // {{{
        /**
         * Enable search (TwinTriggerField)
         */
        ,enable:function() {
            this.setDisabled(false);
        } // eo function enable
        // }}}
        // {{{
        /**
         * Enable search (TwinTriggerField)
         */
        ,disable:function() {
            this.setDisabled(true);
        } // eo function disable
        // }}}
        // {{{
        /**
         * private (re)configures the plugin, creates menu items from column model
         */
        ,reconfigure:function() {
            // {{{
            // remove old items
            var menu = this.menu;
            menu.removeAll();
    
            // add Select All item plus separator
            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.checked;
                        item.parentMenu.items.each(function(i) {
                            if(item !== i && i.setChecked && !i.disabled) {
                                i.setChecked(checked);
                            }
                        });
                    }
                },'-');
            }
    
            // }}}
            // {{{
            // add new items
            var columns = this.grid.headerCt.items.items;
            var group = undefined;
            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.dataIndex;
                    });
                    if(!disable) {
                        menu.add({
                            xtype: 'menucheckitem',
                            text: column.text,
                            hideOnClick: false,
                            group:group,
                            checked: 'all' === this.checkIndexes,
                            dataIndex: column.dataIndex,
                        });
                    }
                }
            }, this);
            // }}}
            // {{{
            // check items
            if(this.checkIndexes instanceof Array) {
                Ext.each(this.checkIndexes, function(di) {
                    var item = menu.items.findBy(function(itm) {
                        return itm.dataIndex === di;
                    });
                    if(item) {
                        item.setChecked(true, true);
                    }
                }, this);
            }
            // }}}
            // {{{
            // disable items
            if(this.readonlyIndexes instanceof Array) {
                Ext.each(this.readonlyIndexes, function(di) {
                    var item = menu.items.findBy(function(itm) {
                        return itm.dataIndex === di;
                    });
                    if(item) {
                        item.disable();
                    }
                }, this);
            }
            // }}}
    
        } // eo function reconfigure
        // }}}
    
    }); // eo extend
    
    // eof
    View Code
    使用方法

    非常简单,代码如下:

    Ext.define('WMS.view.SystemGrid', {
        extend: 'Ext.grid.Panel',
        alias: 'widget.SystemGrid',
    .................
    features: [
            {
                ftype: 'searching',
                minChars: 2,
                 150,
                mode: 'remote',//远程还是本地store
                position: 'top/bottom',//状态栏还是工具栏
                iconCls: 'Zoom',//图标
                menuStyle: 'checkbox/radiobox',//单选还是多选
                showSelectAll: true,   //是否显示全选按钮
                checkIndexes: ["SysName"],       //默认是否选择所有的列
                disableIndexes: ["CreateUser", "CreateTime", "ModifyUser", "ModifyTime", "Disable"]          //禁止那些列参与查询
            }
        ],        
    
    //其他参数参照searching的源代码
    查看产生的URL

    ok,收工。

    下一篇文章将会介绍,MVC如果获取参数,以及如何将Extjs查询的参数动态转换为EntityFramework的Expression<Func<T, bool>>,构造查询SQL(http://www.cnblogs.com/qidian10/p/3209458.html)

  • 相关阅读:
    使用反射和HttpServlet类制作一个简单的web层框架
    [剑指offer]跳台阶问题&动态规划求解
    [剑指offer]旋转数组的最小值
    java实现大锤的自动校对程序(字节校招,字符串问题)
    栈结构的java实现&括号匹配问题
    单链表结构及链表反转操作java代码实现
    排序算法的java实现
    Ajax+JSON
    Jquery
    Filter+Listener
  • 原文地址:https://www.cnblogs.com/qidian10/p/3209439.html
Copyright © 2020-2023  润新知