1. #1
    Sencha User
    Join Date
    Jun 2009
    Posts
    29
    Vote Rating
    2
    JIMECKELS is on a distinguished road

      0  

    Default Multi-sort plugin

    Multi-sort plugin


    This is my first plugin, and rather simple, but figured I would share it for feedback, and perhaps others might find it helpful.

    The goal of this plugin was to allow a grid to have multi-sorting by holding shift while clicking columns. To remove the sorting, click a column by itself to sort by only that column.

    I have a separate plugin for removing sorting altogether, but that's something a bit more muddled as it shares alot of other stuff.


    Any feedback is welcome.

    Code:
    /**
     * Plugin that enables a mulit-sorting by holding shift and clicking column headers
     *
     * @author Jim Eckels (jeckels@parkcitygroup.com)
     * @version 1.0 (tested against 4.2.1)
     * @updated 2013-04-20
     * Initial draft
     * @updated 2013-05-03
     * Use header tooltip to display what the current sort order applied is
     * @updated 2013-10-21
     * Preserve a column's original sortable preference
     * @updated 2013-12-10 
     * Check which sorters are available in the store. Listen for staterestore event too.
     * @updated 2014-08-22 
     * Fixed bug with tooltip on clearing sorts
    */
    Ext.define('Ext.ux.grid.plugin.MultiSort', {
        extend: 'Ext.AbstractPlugin',
        alias: 'plugin.multisort',
        mixins: {
            observable: 'Ext.util.Observable'
        },
        
        localeProperties: {
            sortTipText:    ''
        },
        
        // @public
        showToolTip: true,
        sortTipText: 'Sorted by:',
        
        // @private
        _sortCols: [],
        _grid: undefined,
        _toolTip: undefined,
        
        init: function(grid) {
            var me = this;
    
    
            me.gridListeners = grid.on({
                afterrender:    me.resetup,
                reconfigure:    me.resetup,
                staterestore:   me.resetup,
                scope:          me,
                destroyable:    true
            });
            
            grid.addEvents('multisortchange');
        },
        
        destroy: function(){
            var me = this;
            
            Ext.destroy(me.gridListeners);
            me.unsetup(me._grid);
    
    
            me.callParent(arguments);
            
            delete(me.gridListeners);
        },
        
        // private
        setup: function(grid) {
            var me = this,
                cols = grid.headerCt.getGridColumns();
                
            me._grid = grid;
            me.colsMap = Ext.Array.toValueMap(cols, 'dataIndex');
            
            me.gridHeaderListeners = grid.on({
                headerclick:    me.onColumnClicked, 
                scope:          me,
                destroyable:    true
            });
            me.storeListeners = grid.store.on({
                refresh:        me.onStoreRefresh,
                scope:          me,
                destroyable:    true
            });
            
            // save the columns sortable status
            Ext.Array.each(cols, function(c){
                if(!Ext.isDefined(c.multisortable)){
                    c.multisortable = c.sortable;
                }
                // cancel the default sorting handling
                c.sortable = false;
                delete(c.sortState);
            });
            
            me.updateSortedColumns();
        },
        
        unsetup: function(grid) {
            var me = this;
            
            Ext.destroy(me.gridHeaderListeners, me.storeListeners);
            delete me.colsMap;
    
    
            me.clearToolTip();
            me._sortCols = [];
            me._grid = null;
        },
        
        resetup: function (grid) {
            this.unsetup(grid);
            this.setup(grid);
        },
        
        /**
        * Check what sorters are available on the store and mark the columns as sorted
        * 
        */
        updateSortedColumns: function(){
            var me = this,
                sorters = me._grid.getStore().sorters;
            
            // clear all sorted columns
            Ext.Array.each(me._grid.headerCt.getGridColumns(), function(c){
                c.setSortState(null, true, true);
            });
            
            sorters.each(function(sorter){
                var c = me.colsMap[sorter.property];
                
                if(!c){
                    return;
                }
                
                me.addSortColumn(c, sorter.direction);
            });
            me.createToolTip();
        },
        
        onColumnClicked: function(header, col, e, t, eOpts){
            var me = this,
        	    sorters = [],
                sortState = col.sortState;
    	    
            e.stopEvent();
            
            if(!col.multisortable){ // || (store.isDirty && store.isDirty() && store.remoteSort)){
                return;
            }
    		
            if (e.shiftKey) {
                Ext.each(me._sortCols, function (c) {
                    if(c.sortState) {
                        if( c.id !== col.id ) {
                            sorters.push(
                                {
                                    property: c.dataIndex,
                                    direction: c.sortState
                                }
                            );
                        }
                    }  
                });
            } else {
                Ext.each(me._sortCols, function (c) {
                    if(c.sortState) {
                        // if its not the column that was clicked OR, we were previously multi-sorting, clear sortState and remove icons
                        if( (c.id !== col.id) || (me._sortCols.length > 1) ) {
                            c.setSortState(null, true, true);
                        }
                    }
                });
                me._sortCols = [];
            }
            
            col.sortState = sortState;
            sorters.push(
                {
                    property: col.dataIndex,
                    direction: me.getDirection(col)
                }
            );
                
            me._grid.store.sort(sorters);
        },
        
        addSortColumn: function(col, sortState){
             var me = this, 
                exists = false,
                colToMove = undefined;
    
    
            Ext.each(me._sortCols, function (c) {
                if( c.id === col.id ) {
                    colToMove = c;
                    exists = true;
                }
            });
            
            if(colToMove){
                Ext.Array.remove(me._sortCols,colToMove);
                Ext.Array.push(me._sortCols,colToMove);
            }
            
            if( !exists ) {
                me._sortCols.push(col);
            }
            
            // when there is only one column sorted then the direction is changed automatically
            if(me._sortCols.length > 1 || Ext.isEmpty(col.sortState)){
                col.setSortState(sortState, true, true);
            }
        },
        
        getDirection: function(col){
            return (col.sortState == 'ASC' ) ? 'DESC' : 'ASC';
        },
        
        createToolTip: function(){
            var me = this,
                tip = '';
            
            if( me.showToolTip ) {
                me.clearToolTip();
    
    
                Ext.each(me._sortCols, function (c) {
                    tip += '<br/>' + c.text;
                });
    			
    			if(me._sortCols && me._sortCols.length>0){
    				me._toolTip = Ext.create('Ext.tip.ToolTip',{
    					target: me._grid.headerCt.el,
    					html: me.sortTipText + tip,
    					renderTo: Ext.getBody()
    				});
    			}
            }
        },
        
        // @public
        clearToolTip: function () {
            var me = this;
            if(me._toolTip) {
                me._toolTip.setTarget(undefined);
                Ext.destroy(me._toolTip);
            }
        },
        
        /**
        * The store was refreshed and the sorting might have changed. Let's update the grid columns sort state.
        * 
        * @param store
        */
        onStoreRefresh: function(store){
            this.updateSortedColumns();
        }
    });
    Last edited by JIMECKELS; 5 Oct 2014 at 4:05 PM. Reason: updated plugin code.

  2. #2
    Sencha - Support Team slemmon's Avatar
    Join Date
    Mar 2009
    Location
    Boise, ID
    Posts
    6,062
    Vote Rating
    215
    slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of slemmon has much to be proud of

      0  

    Default


    Thanks for sharing!

  3. #3
    Sencha User
    Join Date
    Nov 2011
    Posts
    15
    Vote Rating
    0
    4lenour is on a distinguished road

      0  

    Default


    how to implement this plugin

  4. #4
    Sencha User
    Join Date
    Jun 2009
    Posts
    29
    Vote Rating
    2
    JIMECKELS is on a distinguished road

      0  

    Default Re: how to use

    Re: how to use


    on a grid, add

    Code:
    requires: [
        'Ext.ux.grid.MultiSort'
    ],
    plugins: [
        { ptype: 'multisort' }
    ],
    ...
    That's it.

    You should now be able to use shift-clicks to add sorting depth. Clicking a column without shift resets to sort by that column only

  5. #5
    Ext JS Premium Member
    Join Date
    Oct 2008
    Location
    California, USA
    Posts
    65
    Vote Rating
    2
    Supergibbs is on a distinguished road

      0  

    Lightbulb MultiSort ignores sortable config

    MultiSort ignores sortable config


    During setup MultiSort sets all column sortable to false to override the sorting functionality but if the column was set to sortable: false already, this is lost. The following additions fix the issue:


    Code:
        setup: function(grid) {
             var me = this;
            me._grid = grid;
    
            Ext.each(me._grid.headerCt.getGridColumns(), function (c) {
                 c.origSortable = c.sortable; //Add This
                 c.sortable = false;
                 c.on('headerclick',me.onColumnClicked, me);
             }, me);
         },
         
         onColumnClicked: function(header, col, e, t, eOpts){
                var me = this, sorters = [];
              
                e.stopEvent();
    
                if (!col.origSortable) //Add This
                     return;

  6. #6
    Sencha User SurenderBhyan1's Avatar
    Join Date
    Nov 2013
    Posts
    24
    Vote Rating
    2
    SurenderBhyan1 is on a distinguished road

      0  

    Default Multisort plugin breaking the default single sorting too in EXT 5

    Multisort plugin breaking the default single sorting too in EXT 5


    Hi

    This multisort plugin is working awesome upto EXT Js version 4.2.1
    BUT
    in case of EXT Version 5 (any build) it is getting break and also breaking the Ext JS default single column sorting too

    Below is a simple fiddle

    https://fiddle.sencha.com/?framework...5.0#fiddle/9vs

    Step to Reproduce:

    Click any of the grid column header, nothing getting happens (Error in console too from ext-all js script)

    Expected Result : Single sort and multisorting should work fine.

    Snapshot:

    MultisortPlugin_BREAK.jpg
    Surender Bhyan
    Mohali



  7. #7
    Sencha Premium Member
    Join Date
    Apr 2014
    Location
    Vancouver
    Posts
    4
    Vote Rating
    0
    mmacret is on a distinguished road

      0  

    Default


    I fixed the bug with Extjs 5.

    Here is the fiddle:

    https://fiddle.sencha.com/?framework...ddle/a2nCheers!

  8. #8
    Sencha User SurenderBhyan1's Avatar
    Join Date
    Nov 2013
    Posts
    24
    Vote Rating
    2
    SurenderBhyan1 is on a distinguished road

      0  

    Default


    Hi mmacret,

    I have tested your plugin updated in script and merged that in my project too.
    Its working great now.
    Thanks a lot Man.
    Surender Bhyan
    Mohali



  9. #9
    Sencha User
    Join Date
    Oct 2014
    Posts
    1
    Vote Rating
    0
    SumitChaudhary is on a distinguished road

      0  

    Default This plugin is not working on Ext js 5.

    This plugin is not working on Ext js 5.


    Quote Originally Posted by mmacret View Post
    I fixed the bug with Extjs 5.

    Here is the fiddle:

    https://fiddle.sencha.com/?framework...ddle/a2nCheers!
    File is not exits on above url. Please provide the link.

  10. #10
    Sencha User SurenderBhyan1's Avatar
    Join Date
    Nov 2013
    Posts
    24
    Vote Rating
    2
    SurenderBhyan1 is on a distinguished road

      0  

    Default


    Quote Originally Posted by SumitChaudhary View Post
    File is not exits on above url. Please provide the link.
    Hi Sumit,

    Please pick up right URL (remove Cheers! from last)

    https://fiddle.sencha.com/?framework...5.0#fiddle/a2n
    Surender Bhyan
    Mohali