Success! Looks like we've fixed this one. According to our records the fix was applied for EXTJS-9491 in 4.2.3.
  1. #1
    Ext JS Premium Member
    Join Date
    Aug 2011
    Location
    Greenville, SC
    Posts
    127
    Vote Rating
    12
    bmacdon1 will become famous soon enough

      0  

    Default [4.2.2] Grid Selection not deselecting record after loading new data with an id

    [4.2.2] Grid Selection not deselecting record after loading new data with an id


    Ext version tested:
    • Ext 4.1.3
    • Ext 4.2.2
    Browser versions tested against:
    • FF 25.0.1
    • Chrome 31.0.1650.57 m
    DOCTYPE tested against:
    • <!DOCTYPE HTML>
    Description:
    • If you load two different sets of data into a store using data with an "id" property, the selection model does not deselect the record correctly because it thinks you are using the same record (when loading a store through loadData). There was a function added inside of Ext.selection.Model class called "storeHasSelected". This appears to be a reason this is occurring. However, it could have something to do with useLinearSearch added to the indexOf function inside of AbstractMixedCollection. In previous version of Extjs 4 (verified in 4.1.3), the row would be deselected.
    Code:
    storeHasSelected: function(record) {
        var store = this.store,
            records,
            len, id, i;
        
        // If two different sets of data are loaded, this check causes the selection model to think it needs to be reselected and does not fire the select event because
        // the selection model does not think it has been changed.
        if (record.hasId() && store.getById(record.getId())) {
            return true;
        } else {
            records = store.data.items;
            len = records.length;
            id = record.internalId;
    
    
            for (i = 0; i < len; ++i) {
                if (id === records[i].internalId) {
                    return true;
                }
            }
        }
        return false;
    },

    Steps to reproduce the problem:
    • Setup a simple grid with two different data sets and load the first set of data with loadData.
    • Select a record and load the second set of data using loadData.
    The result that was expected:
    • When loading the second set of data, the record should be deselected.
    The result that occurs instead:
    • The new data record is selected.
    Additional debugging:
    • I have created a sample grid in the example.zip file to illustrate the problem. I used the following data set for my test.
    Data set A:
    Code:
    [
        {
            "id": "1", //comment this out for second test
            "DATA1":"1",
            "DATA2":"2",
            "DATA3":"3",
            "DATA4":"4",
            "DATA5":"5"
        },
        {
            "id": "2", //comment this out for second test
            "DATA1":"11",
            "DATA2":"22",
            "DATA3":"33",
            "DATA4":"44",
            "DATA5":"55"
        }
    ]

    Data set B:
    Code:
    [
        {
            "id": "1", //comment this out for second test
            "DATA1":"A",
            "DATA2":"B",
            "DATA3":"C",
            "DATA4":"D",
            "DATA5":"E"
        },
        {
            "id": "2", //comment this out for second test
            "DATA1":"AA",
            "DATA2":"BB",
            "DATA3":"CC",
            "DATA4":"DD",
            "DATA5":"EE"
        }
    ]

    Test 1:
    • Go to the index.html page and let the data load.
    • Select the second record containing the column field 1 and value 11
    • Click the Load New Data record
    • Notice new data appears in column field 1. The value is now AA. The row is still highlighted.
    The row was not deselected event though the loadData function created a compeletly new record because the "id" property remained the same. Why would you want to select the same "id" if the data is different?


    Test: 2
    • Open the index.html in a text editor and comment out all of the "id" properties for the data.
    • Go to the index.html page and let the data load.
    • Select the second record containing the column field 1 and value 11
    • Click the Load New Data record
    • Notice new data appears in column field 1. The value is now AA and the row is no longer highlight. This is because storeHasSelected check for id does not return a value and the interalId should be used instead.
    Attached Files

  2. #2
    Ext JS Premium Member
    Join Date
    Aug 2011
    Location
    Greenville, SC
    Posts
    127
    Vote Rating
    12
    bmacdon1 will become famous soon enough

      0  

    Default


    Here is a fiddle that shows more of the problem. If you look at the console.logs (should do this in chrome or firefox), then you can see the selected record is retained even though it is no longer in the store. If I were doing a real app this would be a lot cleaner, but it is based on my example.zip.

    https://fiddle.sencha.com/#fiddle/22t

    I
    f you swap to 4.1.1 classic, you will see the correct behavior.

  3. #3
    Ext JS Premium Member
    Join Date
    Aug 2011
    Location
    Greenville, SC
    Posts
    127
    Vote Rating
    12
    bmacdon1 will become famous soon enough

      0  

    Default


    I ended up filing this with support and here is the Extjs bug number they gave for issue.


    EXTJSIV-11849

  4. #4
    Sencha Premium Member
    Join Date
    Aug 2012
    Location
    Houston
    Posts
    8
    Vote Rating
    2
    elee100 is on a distinguished road

      1  

    Default


    Any updates on the status of this bug? Is there a workaround for this bug?

  5. #5
    Ext JS Premium Member
    Join Date
    Aug 2011
    Location
    Greenville, SC
    Posts
    127
    Vote Rating
    12
    bmacdon1 will become famous soon enough

      0  

    Default


    Haven't heard anything else from sencha. However, I did find this post:


    http://www.sencha.com/forum/showthre...ect-data/page2


    Apparently, its an old known issue. I am not very happy with my fix, but it appears to get the job done. I created an override for the refresh function of the Ext.selection.Model and set the store.data MixedCollection to useLinearSearch. This will tell it to look for the data by the actual data itself instead of looking at keys. You will see a comment like // ADDED - @422. This is where I made my change.


    Code:
    refresh: function() {
        var me = this,
            store = me.store,
            rec,
            toBeSelected = [],
            toBeReAdded = [],
            oldSelections = me.getSelection(),
            len = oldSelections.length,
            selection,
            change,
            i = 0,
            lastFocused = me.getLastFocused();
    
    
        // ADDED - @422 - This is a temp fix for an indexOf change.  It is causing problems with selection models on grids because
        // if you have two completely sets of data that return an id with the response, the selection model thinks that the ids are identical and
        // prevent deselection of the record.
        store.data.useLinearSearch = true;
    
    
        // Not been bound yet.
        if (!store) {
            return;
        }
    
    
        // Add currently records to the toBeSelected list if present in the Store
        // If they are not present, and pruneRemoved is false, we must still retain the record
        for (; i < len; i++) {
            selection = oldSelections[i];
            if (store.indexOf(selection) !== -1) {
                toBeSelected.push(selection);
            }
    
    
            // Selected records no longer represented in Store must be retained
            else if (!me.pruneRemoved) {
                // See if a record by the same ID exists. If so, select it
                rec = store.getById(selection.getId());
                if (rec) {
                    toBeSelected.push(rec);
                }
                // If it does not exist, we have to re-add it to the selection
                else {
                    toBeReAdded.push(selection)
                }
            }
    
    
            // In single select mode, only one record may be selected
            if (me.mode === 'SINGLE' && toBeReAdded.length) {
                break;
            }
        }
    
    
        // there was a change from the old selected and
        // the new selection
        if (me.selected.getCount() != (toBeSelected.length + toBeReAdded.length)) {
            change = true;
        }
    
    
        // ADDED - @422 remove our temp fix from above.
        delete store.data.useLinearSearch
    
    
        me.clearSelections();
    
    
        if (store.indexOf(lastFocused) !== -1) {
            // restore the last focus but supress restoring focus
            me.setLastFocused(lastFocused, true);
        }
    
    
        if (toBeSelected.length) {
            // perform the selection again
            me.doSelect(toBeSelected, false, true);
        }
    
    
        // If some of the selections were not present in the Store, but pruneRemoved is false, we must add them back
        if (toBeReAdded.length) {
            me.selected.addAll(toBeReAdded);
    
    
            // No records reselected.
            if (!me.lastSelected) {
                me.lastSelected = toBeReAdded[toBeReAdded.length - 1];
            }
        }
    
    
        me.maybeFireSelectionChange(change);
    }

  6. #6
    Sencha Premium Member
    Join Date
    Aug 2012
    Location
    Houston
    Posts
    8
    Vote Rating
    2
    elee100 is on a distinguished road

      1  

    Default


    Thanks for the help. It does look like the issue is the useLinearSearch in the indexOf method.
    It may be my situation is slightly different. It is after adding the new record and saving it (i.e. record A) and it updates the id property. When you select a different record on the grid (record B ), record A is not removed from the 'selected' property in the selection model. So when you try to select record A again on the grid, it doesn't get 'selected' because it thinks it's already selected.

    I had to override the constuctor instead of the refresh in the Ext.selection.model

    Code:
    constructor: function (cfg) {                var me = this;
    
    
                    cfg = cfg || {};
                    Ext.apply(me, cfg);
    
    
                    me.addEvents(
                        /**
                         * @event
                         * Fired after a selection change has occurred
                         * @param {Ext.selection.Model} this
                         * @param {Ext.data.Model[]} selected The selected records
                         */
                        'selectionchange',
                        /**
                         * @event
                         * Fired when a row is focused
                         * @param {Ext.selection.Model} this
                         * @param {Ext.data.Model} oldFocused The previously focused record
                         * @param {Ext.data.Model} newFocused The newly focused record
                         */
                        'focuschange'
                    );
    
    
                    me.modes = {
                        SINGLE: true,
                        SIMPLE: true,
                        MULTI: true
                    };
    
    
                    // sets this.selectionMode
                    me.setSelectionMode(cfg.mode || me.mode);
    
    
                    // maintains the currently selected records.
                    me.selected = new Ext.util.MixedCollection(null, me.getSelectionId);
                    
                    me.callParent(arguments);
                    //Tempoary fix
                    me.selected.useLinearSearch = true;
    
    
                }

  7. #7
    Ext JS Premium Member
    Join Date
    Aug 2011
    Location
    Greenville, SC
    Posts
    127
    Vote Rating
    12
    bmacdon1 will become famous soon enough

      0  

    Default


    Thanks for the response. I wrote my own grid save because we didn't have the time to rewrite our middle tier. I'll add this to my internal documentation.

Thread Participants: 1