Hybrid View

  1. #1
    Sencha User
    Join Date
    Dec 2011
    Posts
    2
    Answers
    1
    Vote Rating
    0
    William G is on a distinguished road

      0  

    Question Answered: Ext.grid.Panel multiSelect issue

    Answered: Ext.grid.Panel multiSelect issue


    Hello. I believe I have hit a bug with the multiSelect functionality in the Ext.grid.Panel component. Has anyone else seen the following and figured out a fix?

    Steps to recreate:
    1. Create a standard Ext.grid.Panel with multiple records in it and turn "multiSelect: true"
    Note that you can just go to the documentation page http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.Panel and insert the multiSelect: true line right into there and flip to live preview.

    2. Select the top row, then press and hold shift and click on the second row, then the third row, then the fourth. You would expect to see all 4 rows selected but instead you just get the last two.

    3. For reference, release the shift and select the bottom row (4th row). Now press and hold shift and select the 3rd row, then the 2nd row, then the 1st row. You now see all four rows selected.

    Anyone found a way to fix this?

  2. So I traced deeper and deeper into the Ext source code. I discovered that if you make your selections from bottom up then the "last selected" property stays at the first row you selected. But if you select from top down, then it keeps changing to the last row you selected. I walked up the stack trace until I found where the code handles top down different from bottom up.

    To fix this, I overrode the Ext.selection.Model.selectRange I kept all of the existing code but added in a records.reverse() line in there with a tiny flag to see f you need it or not. Take a look below.

    Code:
     Ext.override(Ext.selection.Model, {
            /**
             * Selects a range of rows if the selection model {@link #isLocked is not locked}.
             * All rows in between startRow and endRow are also selected.
             * @param {Ext.data.Model/Number} startRow The record or index of the first row in the range
             * @param {Ext.data.Model/Number} endRow The record or index of the last row in the range
             * @param {Boolean} keepExisting (optional) True to retain existing selections
             */
            selectRange : function(startRow, endRow, keepExisting, dir){
                var me = this,
                    store = me.store,
                    selectedCount = 0,
                    i,
                    tmp,
                    dontDeselect,
                    records = [];
    
                if (me.isLocked()){
                    return;
                }
    
                if (!keepExisting) {
                    me.deselectAll(true);
                }
    
                if (!Ext.isNumber(startRow)) {
                    startRow = store.indexOf(startRow);
                }
                if (!Ext.isNumber(endRow)) {
                    endRow = store.indexOf(endRow);
                }
    
                // WG: create a flag to see if we are swapping
                var swapped = false;
                // ---
                
                // swap values
                if (startRow > endRow){
                    // WG:  set value to true for my flag
                    swapped = true;
                    // ----
                    tmp = endRow;
                    endRow = startRow;
                    startRow = tmp;
                }
    
                for (i = startRow; i <= endRow; i++) {
                    if (me.isSelected(store.getAt(i))) {
                        selectedCount++;
                    }
                }
    
                if (!dir) {
                    dontDeselect = -1;
                } else {
                    dontDeselect = (dir == 'up') ? startRow : endRow;
                }
    
                for (i = startRow; i <= endRow; i++){
                    if (selectedCount == (endRow - startRow + 1)) {
                        if (i != dontDeselect) {
                            me.doDeselect(i, true);
                        }
                    } else {
                        records.push(store.getAt(i));
                    }
                }
                
                //WG:  START  CHANGE
                // This is my fix, we need to flip the order
                // for it to correctly track what was selected first.
                if(!swapped){
                    records.reverse();
                }
                //WG:  END CHANGE
                
                
                
                me.doMultiSelect(records, true);
            }
        });

  3. #2
    Sencha User
    Join Date
    Dec 2011
    Posts
    2
    Answers
    1
    Vote Rating
    0
    William G is on a distinguished road

      0  

    Default My Solution

    My Solution


    So I traced deeper and deeper into the Ext source code. I discovered that if you make your selections from bottom up then the "last selected" property stays at the first row you selected. But if you select from top down, then it keeps changing to the last row you selected. I walked up the stack trace until I found where the code handles top down different from bottom up.

    To fix this, I overrode the Ext.selection.Model.selectRange I kept all of the existing code but added in a records.reverse() line in there with a tiny flag to see f you need it or not. Take a look below.

    Code:
     Ext.override(Ext.selection.Model, {
            /**
             * Selects a range of rows if the selection model {@link #isLocked is not locked}.
             * All rows in between startRow and endRow are also selected.
             * @param {Ext.data.Model/Number} startRow The record or index of the first row in the range
             * @param {Ext.data.Model/Number} endRow The record or index of the last row in the range
             * @param {Boolean} keepExisting (optional) True to retain existing selections
             */
            selectRange : function(startRow, endRow, keepExisting, dir){
                var me = this,
                    store = me.store,
                    selectedCount = 0,
                    i,
                    tmp,
                    dontDeselect,
                    records = [];
    
                if (me.isLocked()){
                    return;
                }
    
                if (!keepExisting) {
                    me.deselectAll(true);
                }
    
                if (!Ext.isNumber(startRow)) {
                    startRow = store.indexOf(startRow);
                }
                if (!Ext.isNumber(endRow)) {
                    endRow = store.indexOf(endRow);
                }
    
                // WG: create a flag to see if we are swapping
                var swapped = false;
                // ---
                
                // swap values
                if (startRow > endRow){
                    // WG:  set value to true for my flag
                    swapped = true;
                    // ----
                    tmp = endRow;
                    endRow = startRow;
                    startRow = tmp;
                }
    
                for (i = startRow; i <= endRow; i++) {
                    if (me.isSelected(store.getAt(i))) {
                        selectedCount++;
                    }
                }
    
                if (!dir) {
                    dontDeselect = -1;
                } else {
                    dontDeselect = (dir == 'up') ? startRow : endRow;
                }
    
                for (i = startRow; i <= endRow; i++){
                    if (selectedCount == (endRow - startRow + 1)) {
                        if (i != dontDeselect) {
                            me.doDeselect(i, true);
                        }
                    } else {
                        records.push(store.getAt(i));
                    }
                }
                
                //WG:  START  CHANGE
                // This is my fix, we need to flip the order
                // for it to correctly track what was selected first.
                if(!swapped){
                    records.reverse();
                }
                //WG:  END CHANGE
                
                
                
                me.doMultiSelect(records, true);
            }
        });