[FIXED] [#158] [2.x] Grid horizontal scrollbar jumps back to beginning when selecting a record

Page 3 of 3 FirstFirst 123
  1. #21
    The CellEditing plugin re-focus the view after editing. It causes resetting of scrolling.

    Actually, the entire problem is the fact that IE resets scrolling on focus. It is specific to IE and it is quite a frustrating behavior.

    So, likewise the previous override of the focusRow method, you can ignore re-focusing after editing.
    Ext.grid.plugin.CellEditing.override({
        onEditComplete : function(ed, value, startValue) {
            var me = this,
                activeColumn = me.getActiveColumn(),
                context = me.context,
                record;
    
            if (activeColumn) {
                record = context.record;
    
                me.setActiveEditor(null);
                me.setActiveColumn(null);
                me.setActiveRecord(null);
        
                context.value = value;
                if (!me.validateEdit()) {
                    return;
                }
    
                if (!record.isEqual(value, startValue)) {
                    record.set(activeColumn.dataIndex, value);
                }
    
                if (!Ext.isIE) { // the fix
                    context.view.focus(false, true);
                }
    
                me.fireEvent('edit', me, context);
                me.editing = false;
            }
        }
    });
    With that override the scroll doesn't jump to the begging.

    I have to point here that backstage effects are possible. Due to override the focusRow method doesn't do its job in IE, i.e. it doesn't actually focus a row.

    As for editing, the view is not refocused after editing. It means that, for example, navigating via arrow keys is not going to work, probably. Maybe, something else.

    Well, these ramifications might be OK for you. If no, I suggest you to consider another approach - saving scrolling and restore when it is lost (i.e. after focusing). Unfortunately, it also have quite a big disadvantage. At first the scroll position resets, then it restores. Unfortunately, it doesn't happen immediately and it is flickering, shaking. I would say it annoys a lot.

    So, as a summary there are two approaches.

    1. Avoid re-focusing
    Ext.override(Ext.view.Table, {
        focusRow: function (row, delay) {
            var me = this,
                row,
                gridCollapsed = me.ownerCt && me.ownerCt.collapsed,
                record;
    
            if (me.isVisible(true) && !gridCollapsed && (row = me.getNode(row, true)) && me.el) {
                me.scrollRowIntoView(row);
                record = me.getRecord(row);
                rowIdx = me.indexInStore(row);
    
                me.selModel.setLastFocused(record);
    
                if (!Ext.isIE) { // the fix
                    row.focus();
                }
    
                me.focusedRow = row;
                me.fireEvent('rowfocus', record, row, rowIdx);
            }
        }
    });
    
    Ext.grid.plugin.CellEditing.override({
        onEditComplete : function(ed, value, startValue) {
            var me = this,
                activeColumn = me.getActiveColumn(),
                context = me.context,
                record;
    
            if (activeColumn) {
                record = context.record;
    
                me.setActiveEditor(null);
                me.setActiveColumn(null);
                me.setActiveRecord(null);
        
                context.value = value;
                if (!me.validateEdit()) {
                    return;
                }
    
                if (!record.isEqual(value, startValue)) {
                    record.set(activeColumn.dataIndex, value);
                }
    
                if (!Ext.isIE) { // the fix
                    context.view.focus(false, true);
                }
    
                me.fireEvent('edit', me, context);
                me.editing = false;
            }
        },
    
        cancelEdit: function() {
            var me = this,
                activeEd = me.getActiveEditor();
    
            me.setActiveEditor(null);
            me.setActiveColumn(null);
            me.setActiveRecord(null);
            if (activeEd) {
                activeEd.cancelEdit();
    
                if (!Ext.isIE) {
                    me.context.view.focus();
                }
    
                me.callSuper(arguments);
                return;
            }
            // If we aren't editing, return true to allow the event to bubble
            return true;
        }
    });
    2. Restore scroll after focus
    Ext.view.Table.override({
        focusTask: new Ext.util.DelayedTask(),
    
        focusRow: function (row, delay) {
            var me = this,
                row,
                gridCollapsed = me.ownerCt && me.ownerCt.collapsed,
                record;
    
            if (delay) {
                me.focusTask.delay(Ext.isNumber(delay) ? delay : 10, me.focusRow, me, [row, false]);
                return;
            }
    
            me.focusTask.cancel();
    
            if (me.isVisible(true) && !gridCollapsed && (row = me.getNode(row, true)) && me.el) {
                me.scrollRowIntoView(row);
                record = me.getRecord(row);
                rowIdx = me.indexInStore(row);
                me.selModel.setLastFocused(record);
                me.focusedRow = row;
                me.doFocus(row, record, rowIdx);
                me.fireEvent("rowfocus", record, row, rowIdx);
            }
        },
    
        doFocus: function(row, record, rowIdx, scrollLeft) {
            var me = this,
                saveScroll = Ext.isIE,
                scrollLeft;
    
            if (saveScroll) {
                scrollLeft = me.el.getScrollLeft();
            }
    
            row.focus();
    
            if (saveScroll) {
                console.log("scrollLeft: " + scrollLeft);
                me.el.setScrollLeft(scrollLeft);
                me.ignoreScroll = false;
            }
        }
    });
    
    Ext.grid.plugin.CellEditing.override({
        cancelEdit: function() {
            var me = this,
                activeEd = me.getActiveEditor();
    
            me.setActiveEditor(null);
            me.setActiveColumn(null);
            me.setActiveRecord(null);
            if (activeEd) {
                activeEd.cancelEdit();
                me.context.view.focusRow(me.context.rowIdx, 100);
                me.callSuper(arguments);
                return;
            }
    
            return true;
        }
    });
    .Plugins(X.CellEditing()
        .Listeners(events =>
        {
            events.BeforeEdit.Handler = "this.savedScrollLeft = e.grid.getView().el.getScrollLeft();";
            events.Edit.Handler = "e.grid.getView().el.setScrollLeft(this.savedScrollLeft);";
            events.Edit.Delay = 1;
        })
    )
    By the way, I just tested the scenario with v3.0 beta and it appears to be working well. The scroll position doesn't reset and I don't see any flickering/shaking.
  2. #22
    Hi, Daniil:

    The fix that you suggested in #1 and which I adopted for one grid in my app (posted the question here originally: http://forums.ext.net/showthread.php...llbar-in-IE-11) seems to affect the navigation in other grids via the Up/Down keys. I didn't notice at the time because in that grid I used cell selection, while in the others I had row selection turned on.

    All this occurs in IE 11. I have a grid that goes off screen ( it has enough columns that the control shows the horizontal scrollbar). If I scroll to the right to view the rightmost columns and I click on a row, IE 11 does this effect where it scrolls left and it scrolls back in position which has an annoying flashing effect. If I apply the patch at #1 I start to see weird stuff in the grid when I try to use the Up/Down keys. The grid is read-only and it has a checkbox selection model and it behaves weird when I press the up/down keys.

    The approach described in #2 doesn't seem to have any effect, IE 11 still does the scroll thing.

    So, I am not too sure where this is at.

    As I wrote this post I was pondering whether I should write a sample. The issue can be reproduced using this sample: https://examples2.ext.net/#/GridPane...vent_Creation/

    To reproduce it in IE 11:
    1. Go to the sample above
    2. Click the Add GridPanel button
    3. Shrink the size of the window such that the horizontal bar becomes visible.
    4. Scroll to the last column , Last Updated.
    5. Now, click on any date in the Last Updated column. IE does this flashing effect.

    If you try to apply the #1 patch try to use the UP/Down keys in the grid and see what happens. In my case I also had a checkbox selection model (Multi). If you add one as well and start pressing the Up/Down you'll see the effects.

    3.0.0 has fixed this problem, however, at this time we are not scheduled to do the upgrade. I also have an ExtJs license, so theoretically I could apply their 4.2.2 patch I am reluctant do it. When I compared the source code, the code that they added in 4.2.2 was quite involved, far more complicated than the patch in #1.

    Any suggestions?

    Thanks
  3. #23
    Hi @bogc,

    Yes, it appears the approach #1 breaks key navigation. Well, the workaround was to avoid real focusing, but it is essential for key navigation.

    I will summarize a bit the information about the issue that we are facing in this thread.

    Then you click on a row, it is being focused. Here is the Ext.view.Table's focus method.
    focus: function(selectText, delay) {
        var me = this,
            saveScroll = Ext.isIE && !delay,
            scrollPos;
    
        // IE does horizontal scrolling when row is focused
        if (saveScroll) {
            scrollPos = me.el.dom.scrollLeft;
        }
        this.callParent(arguments);
        if (saveScroll) {
            me.el.dom.scrollLeft = scrollPos;
        }
    }
    As far as you can see it has the specific code to save and then restore the scroll position if it runs in IE. And that is a real problem. IE resets the current scroll position on focusing. I googled it a lot, there is a lot of links where people discuss this problem regardless Ext.NET or ExtJS. The only solution I see is to save and restore the scroll position. Probably, ExtJS team didn't find any other way as well.

    As for ExtJS 4.2.2 I am able to reproduce the same issue. Yes, the TableView's code has been changed significantly, but there is still the save -and-restore-a-scroll-position approach in the doFocus method.

    As for ExtJS 5, as far as I can understand they gave up doing a real focusing and use another approach with new navigation and focusing functionality. I am afraid it is not applicable for ExtJS 4, because it would involve reworking the half of ExtJS or so.

    When I finally realized that there is no approach (at least, I don't see any) to avoid the save-and-restore approach, I focused on that flickering issue that, I totally agree, is very annoying. Unfortunately, I am unable to find a way to avoid or, at least, minimize that flickering issue. I tried a few things. For example, this one:

    <style>
        .flickering-fix * {
            color: white !important;
        }
    </style>
    
    <script>
        Ext.override(Ext.view.Table, {
            focus: function (selectText, delay) {
                var me = this,
                    saveScroll = Ext.isIE && !delay,
                    scrollPos;
    
                // IE does horizontal scrolling when row is focused
                if (saveScroll) {
                    scrollPos = me.el.dom.scrollLeft;
                    me.el.addCls("flickering-fix");
                }
    
                this.callParent(arguments);
    
                if (saveScroll) {
                    me.el.dom.scrollLeft = scrollPos;
                    me.el.removeCls("flickering-fix");
                }
            }
        });
    </script>
    The idea was to "hide" everything then the scroll position resets and restores. Unfortunately, it doesn't help to avoid flickering. Though, flickering changed a bit and, from some point of view, it might be considered better than the original flickering. I don't think it will an appropriate solution for you. Maybe, you will find that even worse. Anyways, I am posting here a full example to let you test it. Moreover, I hope it might help you to come up with some better idea.

    Example
    <%@ Page Language="C#" %>
    
    <%@ Import Namespace="Button=Ext.Net.Button" %>
    
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <script runat="server">
        protected void Button1_Click(object sender, DirectEventArgs e)
        {
            this.BuildGridPanel().AddTo(this.Window1);
    
            // Reference Button by sender argument
            ((Button)sender).Disabled = true;
    
            // Reference Button by .Items Collection
            //this.Window1.TopBar.Toolbar.Items[0].Disabled = true;
    
            // Reference Button directly by .ID
            // this.Button1.Disabled = true;
        }
    
        private GridPanel BuildGridPanel()
        {
            return new GridPanel
            {
                ID = "GridPanel1",
                Border = false,
                Store =  
                {
                    this.BuildStore()
                },
                SelectionModel = 
                { 
                    new CheckboxSelectionModel() { Mode = SelectionMode.Multi }
                },
                ColumnModel =
                {
                    Columns =
                    {
                        new Column 
                        {
                            Text = "Company", 
                            DataIndex = "company",
                            Flex = 1
                        },
                        new Column
                        {
                            Text = "Price",
                            DataIndex = "price",
                            Renderer = { Format = RendererFormat.UsMoney }
                        },
                        new Column
                        {
                            Text = "Change",
                            DataIndex = "change",
                            Renderer = { Fn = "change" }
                        },
                        new Column
                        {
                            Text = "Change",
                            DataIndex = "pctChange",
                            Renderer = { Fn = "pctChange" }
                        },
                        new DateColumn
                        {
                            Text = "Last Updated",
                            DataIndex = "lastChange",
                            Width = 500
                        }
                    }
                },
                View =
                {
                   new Ext.Net.GridView()
                   {
                        StripeRows = true,
                        TrackOver = true 
                   }
                }
            };
        }
    
        private Store BuildStore()
        {
            Store store = new Store
            {
                Model = 
                { 
                    new Model 
                    {
                        Fields = 
                        {
                            new ModelField("company"),
                            new ModelField("price", ModelFieldType.Float),
                            new ModelField("change", ModelFieldType.Float),
                            new ModelField("pctChange", ModelFieldType.Float),
                            new ModelField("lastChange", ModelFieldType.Date, "M/d hh:mmtt")
                        }
                    }
                }
            };
    
            store.DataSource = this.Data;
    
            return store;
        }
    
        private object[] Data
        {
            get
            {
                return new object[]
                {
                    new object[] { "3m Co", 71.72, 0.02, 0.03, "9/1 12:00am" },
                    new object[] { "Alcoa Inc", 29.01, 0.42, 1.47, "9/1 12:00am" },
                    new object[] { "Altria Group Inc", 83.81, 0.28, 0.34, "9/1 12:00am" },
                    new object[] { "American Express Company", 52.55, 0.01, 0.02, "9/1 12:00am" },
                    new object[] { "American International Group, Inc.", 64.13, 0.31, 0.49, "9/1 12:00am" },
                    new object[] { "AT&T Inc.", 31.61, -0.48, -1.54, "9/1 12:00am" },
                    new object[] { "Boeing Co.", 75.43, 0.53, 0.71, "9/1 12:00am" },
                    new object[] { "Caterpillar Inc.", 67.27, 0.92, 1.39, "9/1 12:00am" },
                    new object[] { "Citigroup, Inc.", 49.37, 0.02, 0.04, "9/1 12:00am" },
                    new object[] { "E.I. du Pont de Nemours and Company", 40.48, 0.51, 1.28, "9/1 12:00am" },
                    new object[] { "Exxon Mobil Corp", 68.1, -0.43, -0.64, "9/1 12:00am" },
                    new object[] { "General Electric Company", 34.14, -0.08, -0.23, "9/1 12:00am" },
                    new object[] { "General Motors Corporation", 30.27, 1.09, 3.74, "9/1 12:00am" },
                    new object[] { "Hewlett-Packard Co.", 36.53, -0.03, -0.08, "9/1 12:00am" },
                    new object[] { "Honeywell Intl Inc", 38.77, 0.05, 0.13, "9/1 12:00am" },
                    new object[] { "Intel Corporation", 19.88, 0.31, 1.58, "9/1 12:00am" },
                    new object[] { "International Business Machines", 81.41, 0.44, 0.54, "9/1 12:00am" },
                    new object[] { "Johnson & Johnson", 64.72, 0.06, 0.09, "9/1 12:00am" },
                    new object[] { "JP Morgan & Chase & Co", 45.73, 0.07, 0.15, "9/1 12:00am" },
                    new object[] { "McDonald\"s Corporation", 36.76, 0.86, 2.40, "9/1 12:00am" },
                    new object[] { "Merck & Co., Inc.", 40.96, 0.41, 1.01, "9/1 12:00am" },
                    new object[] { "Microsoft Corporation", 25.84, 0.14, 0.54, "9/1 12:00am" },
                    new object[] { "Pfizer Inc", 27.96, 0.4, 1.45, "9/1 12:00am" },
                    new object[] { "The Coca-Cola Company", 45.07, 0.26, 0.58, "9/1 12:00am" },
                    new object[] { "The Home Depot, Inc.", 34.64, 0.35, 1.02, "9/1 12:00am" },
                    new object[] { "The Procter & Gamble Company", 61.91, 0.01, 0.02, "9/1 12:00am" },
                    new object[] { "United Technologies Corporation", 63.26, 0.55, 0.88, "9/1 12:00am" },
                    new object[] { "Verizon Communications", 35.57, 0.39, 1.11, "9/1 12:00am" },
                    new object[] { "Wal-Mart Stores, Inc.", 45.45, 0.73, 1.63, "9/1 12:00am" }
                };
            }
        }
    </script>
    
    <!DOCTYPE html>
    
    <html>
    <head runat="server">
        <title>Ext.NET v2 Example</title>
    
        <style>
            .flickering-fix * {
                color: white !important;
            }
        </style>
    
        <script>
            Ext.override(Ext.view.Table, {
                focus: function (selectText, delay) {
                    var me = this,
                        saveScroll = Ext.isIE && !delay,
                        scrollPos;
    
                    // IE does horizontal scrolling when row is focused
                    if (saveScroll) {
                        scrollPos = me.el.dom.scrollLeft;
                        me.el.addCls("flickering-fix");
                    }
    
                    this.callParent(arguments);
    
                    if (saveScroll) {
                        me.el.dom.scrollLeft = scrollPos;
                        me.el.removeCls("flickering-fix");
                    }
                }
            });
        </script>
    
        <script>
            var template = '<span style="color:{0};">{1}</span>';
    
            var change = function (value) {
                return Ext.String.format(template, (value > 0) ? "green" : "red", value);
            };
    
            var pctChange = function (value) {
                return Ext.String.format(template, (value > 0) ? "green" : "red", value + "%");
            };
        </script>
    </head>
    <body>
        <form runat="server">
            <ext:ResourceManager runat="server" />
    
            <ext:Window
                ID="Window1"
                runat="server"
                Title="Dynamic GridPanel"
                Layout="FitLayout"
                Height="350"
                Width="600">
                <TopBar>
                    <ext:Toolbar runat="server">
                        <Items>
                            <ext:Button
                                runat="server"
                                Text="Add GridPanel"
                                Icon="Add">
                                <DirectEvents>
                                    <Click OnEvent="Button1_Click">
                                        <EventMask ShowMask="true"
                                            Target="CustomTarget"
                                            CustomTarget="Window1" />
                                    </Click>
                                </DirectEvents>
                            </ext:Button>
                        </Items>
                    </ext:Toolbar>
                </TopBar>
            </ext:Window>
        </form>
    </body>
    </html>
  4. #24
    Daniil, thanks for looking into this. I tested your sample code and the flashing effect is still there, marginally better. I am going to leave the app as is for now.
  5. #25
    Hello! Sencha reports their issue related to this is fixed for some time already, so this should no longer be a problem in recent Ext.NET versions!

    (this does not mean necessarily this has been fixed for Ext.NET 2 as with so many new features on 3.x and 4.x, there are some issues that are simply not feasible to fix on the legacy version!)
    Fabrício Murta
    Developer & Support Expert
Page 3 of 3 FirstFirst 123

Similar Threads

  1. Replies: 19
    Last Post: Jan 05, 2016, 11:43 PM
  2. Replies: 10
    Last Post: Nov 24, 2015, 6:54 PM
  3. [CLOSED] IE7 Horizontal ScrollBar
    By cwolcott in forum 2.x Legacy Premium Help
    Replies: 2
    Last Post: May 01, 2015, 4:13 PM
  4. Replies: 6
    Last Post: Nov 12, 2014, 8:35 PM
  5. Replies: 5
    Last Post: Apr 03, 2013, 5:59 AM

Posting Permissions