[OPEN] [#821] Grid column header interaction (e.g. resize) sometimes triggers unexpected click event

  1. #1

    [OPEN] [#821] Grid column header interaction (e.g. resize) sometimes triggers unexpected click event

    Hi,

    I have an odd problem in both Ext.NET 1.x and 3.x.

    It has taken a while to reproduce in a standalone example, but it seems to require a grid with enough columns to reproduce it (and even then it is not always easy to reproduce).

    Anyway, take this example which is just a simple grid with a few columns:

    <%@ Page Language="C#" %>
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!X.IsAjaxRequest)
            {
                Store1.DataSource = Data;
                Store1.DataBind();
            }
        }
    
        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>Simple Array Grid - Ext.NET Examples</title>
    </head>
    <body>
        <ext:ResourceManager runat="server" />
        
        <ext:GridPanel ID="GridPanel1" runat="server">
            <Store>
                <ext:Store ID="Store1" runat="server">
                    <Model>
                        <ext:Model runat="server">
                            <Fields>
                                <ext:ModelField Name="company" />
                                <ext:ModelField Name="price" Type="Float" />
                                <ext:ModelField Name="change" Type="Float" />
                                <ext:ModelField Name="pctChange" Type="Float" />
                                <ext:ModelField Name="lastChange" Type="Date" DateFormat="M/d hh:mmtt" />
                            </Fields>
                        </ext:Model>
                    </Model>
                    <CustomConfig>
                        <ext:ConfigItem Name="sort" Value="function() {Ext.MessageBox.show({ msg: 'Cannot sort' }); console.trace(); return false;}" Mode="Raw"/>
                    </CustomConfig>
                </ext:Store>
            </Store>
            <ColumnModel>
                <Columns>
                    <ext:Column runat="server" Text="Company" DataIndex="company" Flex="1" />
                    <ext:Column runat="server" Text="Price" DataIndex="price" />
                    <ext:Column runat="server" Text="Change" DataIndex="change" />
                    <ext:Column runat="server" Text="Change" DataIndex="pctChange" />
                    <ext:Column runat="server" Text="1Price" DataIndex="price" />
                    <ext:Column runat="server" Text="1Change" DataIndex="change" />
                    <ext:Column runat="server" Text="2Price" DataIndex="price" />
                    <ext:Column runat="server" Text="2Change" DataIndex="change" />
                    <ext:Column runat="server" Text="3Price" DataIndex="price" />
                    <ext:Column runat="server" Text="3Change" DataIndex="change" />
                    <ext:Column runat="server" Text="3Price" DataIndex="price" />
                    <ext:Column runat="server" Text="3Change" DataIndex="change" />
                    <ext:DateColumn runat="server" Text="Last Updated" DataIndex="lastChange" />
                </Columns>            
            </ColumnModel>       
            <SelectionModel>
                <ext:RowSelectionModel runat="server" />
            </SelectionModel>
        </ext:GridPanel>
    </body>
    </html>
    Notice the custom config
    • I am simulating my real code where I have a subclass of a Store where I override the sort method
    • In this example, I am always forcing the call to Sort to show a message box and return false
    • (Of course, this is silly - you can disable sort - but in my real code I have some conditions to check if sort has to be limited - e.g. too much data for the server to handle, where the grid needs further filtering first, but for the purpose of this issue, this silly example is enough!)


    Now, you would only expect this to fire when the header is clicked, or the grid Sort menu is invoked - and it does.

    But, sometimes, if you resize the column in the right way, it triggers the sort as well. To me it seems that when resizing a column, the moment you let go of the mouse, if the mouse pointer happens to be above one of the adjacent column headers (where you would normally click it to sort by that column) then the event bubbles up and sometimes (not always) it thinks it is a click event on that adjacent column header and it tries to trigger a sort.

    But I cannot understand why it happens intermittently...

    I've attached a screenshot showing a rough idea of the stack trace when it happens. Seems like I cannot attach videos to demonstrate this which might help as I appreciate this is not easy to reproduce sometimes - you have to keep trying to resize the column now and again; quite often it works fine...

    The Ext.NET resource manager script mode is set to debug in web.config, so the line numbers written in the trace output in the screenshot should hopefully help. Though I am not sure which ones you may want - I could write them here, though may increase the size of this post quite a bit, and you might be able to reproduce and the console.trace can help show you the exact line number more interactively, perhaps?

    In the stack trace, is this relevant?

    Ext.grid.header.Container.override.onHeaderCtEvent @ ext.axd?v=19151:14622
    It is an override of onHeaderCtEvent:

    Ext.grid.header.Container.override({
        onHeaderCtEvent: function (e, t) {
            if (e.getTarget('.x-grid-header-widgets', this.el)) {
                return false;
            }
    
            return this.callParent(arguments);
        },
    The stack trace shows this.callParent(arguments) being called. Could it be another condition is needed to return false? It may be tricky unless you know it was a resize column drag event that started this all in the first place, given how intermittent it is?

    In our real world app this can happen a bit more frequently so it can be quite annoying for users...

    I have a similar issue with 1.x which I will try to reproduce separately and raise as a separate post (I am not working on 2.x so I haven't checked - but I will try to see if that is a problem there as well).

    Let me know if you need more info!
    Attached Thumbnails grid-resize-click-triggered.jpg  
    Last edited by Daniil; Jul 01, 2015 at 10:49 AM. Reason: [OPEN] [#821]
  2. #2
    Please note I can reproduce this problem in Chrome (latest) and IE (I was using IE11 - didn't check the earlier versions at the moment). Firefox seemed okay.
  3. #3
    Hello Anup,

    Thank you for the report! We'll investigate.
  4. #4
    I think it is a different case comparing with v1.

    Found this Sencha forum thread with, probably, the same problem, but, unfortunately, no valuable feedback.
    https://www.sencha.com/forum/showthread.php?287925

    Created an Issue.
    https://github.com/extnet/Ext.NET/issues/821

    Came up with this fix/workaround. Sort of ugly, but appears to be working. Please let me know if it works for you or it doesn't.

    Fix/workaround
    Ext.grid.plugin.HeaderResizer.override({
        onEnd: function (e) { // #821
            var me = this;
    
            me.headerCt.wasDrag = true;
            Ext.defer(function () { delete me.headerCt.wasDrag; }, 50);
            me.callParent(arguments);
        }
    });
    
    Ext.grid.header.Container.override({
        onHeaderCtEvent: function (e, t) {
            var me = this,
                headerEl = me.getHeaderElByEvent(e),
                header, targetEl, activeHeader;
    
            if (me.longPressFired) {
                me.longPressFired = false;
                return;
            }
            if (headerEl && !me.ddLock) {
                header = Ext.getCmp(headerEl.id);
    
                if (header) {
                    targetEl = header[header.clickTargetName];
    
                    if ((!header.isGroupHeader && !header.isContainer) || e.within(targetEl)) {
                        if ((e.type === 'click' || e.type === 'tap') && !me.wasDrag) { // #821, added "&& !me.wasDrag"
                            activeHeader = header.onTitleElClick(e, targetEl, me.sortOnClick);
    
                            if (activeHeader) {
                                me.onHeaderTriggerClick(activeHeader, e, Ext.supports.Touch ? activeHeader.el : activeHeader.triggerEl);
                            } else {
                                me.onHeaderClick(header, e, t);
                            }
                        } else if (e.type === 'contextmenu') {
                            me.onHeaderContextMenu(header, e, t);
                        } else if (e.type === 'dblclick' && header.resizable) {
                            header.onTitleElDblClick(e, targetEl.dom);
                        }
                    }
                }
            }
        }
    });
  5. #5
    Many thanks for looking into this. I will try to look at this at my earliest (though I may be reassigned to something else for a few weeks again, unfortunately), so will try to update you when I can...!

Similar Threads

  1. Replies: 4
    Last Post: May 21, 2015, 4:58 AM
  2. Replies: 9
    Last Post: Feb 15, 2013, 6:21 AM
  3. [CLOSED] How to resize Panel after click event ?
    By Daly_AF in forum 1.x Premium Help
    Replies: 2
    Last Post: Jan 29, 2013, 11:15 AM
  4. resize column header from right to left
    By CarlosS in forum 1.x Help
    Replies: 0
    Last Post: Mar 31, 2012, 1:05 AM
  5. Replies: 2
    Last Post: Feb 01, 2012, 11:16 AM

Posting Permissions