1. #1
    Sencha User
    Join Date
    Oct 2009
    Posts
    21
    Vote Rating
    0
    strimp099 is on a distinguished road

      0  

    Default this.focusEl is undefined error on click of columnGrid header

    this.focusEl is undefined error on click of columnGrid header


    I'm using ExtJs 3.2.2. I wrote a custom context menu to handle a grid's headerclick event. I get a "this.focusEl is undefined error" error when I click the header. I have a feeling it has something to do with the scope in the context menu, but I'm perplexted. FF degrades gracefully and still displays the menu but IE's behavior is unpredictable.

    This is the grid's headerclick event:

    PHP Code:
    headerclick: function(gridcolumnIndexe) { 
        
    e.stopEvent(); 
        var 
    colModel grid.getColumnModel(); 
        var 
    col colModel.getColumnById(colModel.getColumnId(columnIndex)) 
        
    contextMenu.columnId col.id
        
    contextMenu.headerName col.header
        
    contextMenu.showAt(e.getXY()); 

    This is the context menu:

    PHP Code:
    var contextMenu = new Ext.menu.Menu({ 
        
    items: [{ 
            
    id'sort-high-to-low'
            
    cls'xg-hmenu-sort-asc'
            
    text'Sort Ascending within Group' 
        
    },{ 
            
    id'sort-low-to-high'
            
    cls'xg-hmenu-sort-desc'
            
    text'Sort Descending within Group' 
        
    },'-',{ 
            
    id'sort-high-to-low-all'
            
    cls'xg-hmenu-sort-asc'
            
    text'Sort All Ascending' 
        
    },{ 
            
    id'sort-low-to-high-all'
            
    cls'xg-hmenu-sort-desc'
            
    text'Sort All Descending' 
        
    },'-',    { 
            
    id'heatmap'
            
    cls'xg-hmenu-heatmap'
            
    text'Open in Heatmap' 
        
    }], 
        
    listeners: { 
            
    scopethis// not sure if this is correct... 
            
    itemclick: function(item) { 
                switch (
    item.id) { 
                    case 
    'sort-high-to-low'
                        
    Ext.getCmp('backtestGrid').getStore().sort(contextMenu.columnId,'ASC'); 
                        
    this.hide(); 
                        break; 
                    case 
    'sort-low-to-high'
                        
    Ext.getCmp('backtestGrid').getStore().sort(contextMenu.columnId,'DESC'); 
                        
    this.hide(); 
                        break; 
                    case 
    'sort-high-to-low-all'
                        
    Ext.getCmp('backtestGrid').getStore().clearGrouping(); 
                        
    Ext.getCmp('backtestGrid').getStore().sort(contextMenu.columnId,'ASC'); 
                        
    this.hide(); 
                        break; 
                    case 
    'sort-low-to-high-all'
                        
    Ext.getCmp('backtestGrid').getStore().clearGrouping(); 
                        
    Ext.getCmp('backtestGrid').getStore().sort(contextMenu.columnId,'DESC'); 
                        
    this.hide(); 
                        break; 
                    case 
    'heatmap'
                        
    heatmapCallback(contextMenu.headerNamecontextMenu.columnId); 
                        
    this.hide(); 
                        break; 
                } 
            } 
        } 
    }); 
    The second question is when I actually click on one of the context menu items. I get the following error:

    PHP Code:
    this.fireEvent is not a function 
    The first item, for exampple, is a sort. When clicking on the first item, FF will throw the error but still sort the grid. IE does not sort the grid.

    Again, I have a feeling this error has to do with the

    PHP Code:
    this.hide(); 
    statements in each of the case blocks. I suppose this refers to the menu item, not the menu. After clicking on each item, I need to hide the menu. However, even if I comment out the this.hide() statements, the error still occurs.

  2. #2
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    I wasn't able to reproduce your first issue, the menu showed up for me without errors. Possibly some other property of your grid is required to cause the issue to occur. Try putting in a breakpoint on that line and work your way back up the stack to figure out what it's doing. You'll need to be using ext-all-debug.js for that. I'd recommend the Chrome Developer Tools debugger as it copes fine with the large ExtJS JavaScript files. Firebug or the IE debugger are also possibilities.

    Your second issue is also a bit mysterious.

    Firstly, you shouldn't need to hide the menu manually. The menu should disappear by default when an item is clicked, unless the item has hideOnClick: false.

    Secondly, you're correct that your scope is all wrong and this.hide() won't be doing what you want. Exactly what it is scoped to isn't shown in your snippets. You could just do contextMenu.hide() but, as mentioned above, it really shouldn't be necessary.

    What's causing the problem with fireEvent() is altogether less clear. Again I'd suggest a quick dig with a debugger and breakpoints to figure out what event is being fired and which object thinks it's firing it. I agree it looks like a scoping issue but there isn't an obvious candidate in the code you've posted.

  3. #3
    Sencha User
    Join Date
    Oct 2009
    Posts
    21
    Vote Rating
    0
    strimp099 is on a distinguished road

      0  

    Default


    Thanks for your response.

    I couldn't figure out how to avoid the first error so I just temporarily set the function:

    PHP Code:
    headerclick: function(gridcolumnIndexe) {
        
    e.stopEvent();
        var 
    colModel grid.getColumnModel();
        var 
    col colModel.getColumnById(colModel.getColumnId(columnIndex))
        
    contextMenu.columnId col.id; [/FONT][/SIZE]
        
    contextMenu.headerName col.header;
        
    contextMenu.doFocus = function(){}; // prevents the 'this.focusEl is undefined' error
        
    contextMenu.showAt(e.getXY());

    It's not the most elegant solution, but works for now.

    As far as the second error, I experimented with scope, setting it to the menu itself with no luck. Also, I commented out the reference to contextMenu.hide() and I still get the this.fireEvent is not a function error when clicking on the header!

    Further, within the switch-case statement for the itemclick, I tried the each of the following (separately) to hide (the menu does not automatically hide for some reason):

    PHP Code:
     
    this
    .hide(); // after properly setting the scope option
    contextMenu.hide(); // does not work
    Ext.getCmp('contextMenu').hide(); // after setting the ID, does not work 
    I've been trying to debug but I'm struggling. Any other thoughts?

  4. #4
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    There's something very, very strange going on here. I can't help but thinking that the underlying cause of both issues is the same but I don't see it in the code you've posted. Here are some suggestions for digging deeper.
    1. Get rid of your doFocus() override for all of the steps suggested below.
    2. Try completely removing the listeners section from the menu. What happens?
    3. Keeping the listeners removed, reduce the menu down to a single item. Remove the id.
    4. Try putting a breakpoint on the line this.focusEl = this.el.child('a.x-menu-focus'); in the menu's onRender() method. Does focusEl get set?
    5. Put a breakpoint in doFocus(). Has focusEl changed since the onRender() method? Is this the menu?
    6. Try to remove the headerclick from the equation. Show the menu using contextMenu.showAt([20, 20]); somewhere else in the code, e.g. in your Ext.onReady().

    It would also be really useful to know which event causes it to fail on the fireEvent(). Could you use the stacktrace to figure out which event it is trying to fire and what the value of this is on that line?

  5. #5
    Sencha User
    Join Date
    Oct 2009
    Posts
    21
    Vote Rating
    0
    strimp099 is on a distinguished road

      0  

    Default


    1. Get rid of your doFocus() override for all of the steps suggested below.
    Done
    2. Try completely removing the listeners section from the menu. What happens?
    Upon clicking the column header, the menu appears and I get the following:
    PHP Code:
    this.focusEl is undefined
    http
    ://example.com/bin/js/ext-3.2.1/ext-all-debug.js
    Line 36159 
    When I click a menu item, nothing happens but I get the following:
    PHP Code:
    this.fireEvent is not a function
    http://example.com/bin/js/ext-3.2.1/ext-all-debug.js
    Line 10165 
    3. Keeping the listeners removed, reduce the menu down to a single item. Remove the id.
    When the id is removed, I get the following error:
    PHP Code:
    this.focusEl is undefined
    http
    ://example.com/bin/js/ext-3.2.1/ext-all-debug.js
    Line 36159 
    Note line 36159 is the initComponent function for the menu
    4. Try putting a breakpoint on the line this.focusEl = this.el.child('a.x-menu-focus'); in the menu's onRender() method. Does focusEl get set?
    It does not appear to be set.
    5. Put a breakpoint in doFocus(). Has focusEl changed since the onRender() method? Is this the menu?
    It does not appear to have been set or changed.
    6. Try to remove the headerclick from the equation. Show the menu using contextMenu.showAt([20, 20]); somewhere else in the code, e.g. in your Ext.onReady().
    I did this and the menu appeared at 20, 20. However, so did the following error:
    PHP Code:
    this.focusEl is undefined
    http
    ://example.com/bin/js/ext-3.2.1/ext-all-debug.js
    Line 36159 
    Line 36159 is
    PHP Code:
    Ext.form.TriggerField.superclass.onRender.call(thisctposition); 
    This makes me think it is the menu. Further evidence is that when I comment out the contextMenu.showAt(e.getXY()) statement, there is no error.

    This is the stacktrace from the error. I'm struggling a bit to translate...
    PHP Code:
    headerclick(grid=Object initialConfig={...}, title="Indicator Backtest"more...}, columnIndex=6e=Object browserEvent=Event clickbutton=0more...})
    fire()
    fireEvent()
     
    destroy(name="click"e=Object browserEvent=Event clickbutton=0more...})
     
    (?)(
    name="click"e=Object browserEvent=Event clickbutton=0more...})
     
    onClear(name="click"e=Object browserEvent=Event clickbutton=0more...})
     
    onUpdate(e=Object browserEvent=Event clickbutton=0more...})
     
    h(e=Object browserEvent=Event clickbutton=0more...})
     
    Object browserEvent=Event resizebutton=-1more...}
     
    this.focusEl is undefined 

  6. #6
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    Some more thoughts. Are you using any other adapters or are you just using ext-base? Are you using any patches or overrides that change classes in the Ext namespace (such things are commonly used for patching bugs)?

    You seem to have switched from ExtJS 3.2.2 to 3.2.1. Be very careful with that, ext-all and ext-base need to tie up.

    In the space of a couple of paragraphs you change your mind about what line 36159 is and I don't think you found it in either case. I just had a look myself and it's the line this.focusEl.focus(); in doFocus().

    Line 10165 is firing the beforehide event and is the first line of the hide() method on Ext.Component. It's consistent with everything else you're seeing as that error will stop it from hiding.

    That stacktrace is pretty horrific. Which debugger gave you that? I strongly recommend giving the Google Chrome debugger a try... simple stacktraces with line numbers and click through to the code.

    I've knocked up this section of code to try to give us further info. Most of it is pretty generic but I've added a little bit on the end for spying on menus. Put it in your code just after you include Ext and it should give you some useful logging. It'll be useful for me to diagnose further even if it's a little cryptic to you.

    Code:
    (function() {
        var msgs = [], logWin, logCount = 0, lastCount;
    
        var logShow = function() {
            alert(msgs.reverse().join('\n'));
        };
    
        setTimeout(function() {
            logShow();
        }, 1000);
    
        var log = function(msg) {
            msgs.unshift(msg);
            logCount++;
    
            if (msgs.length > 100) {
                msgs.length = 100;
            }
        };
    
        log('Verifying ExtJS');
    
        if (!window['Ext']) {
            log('Ext not found, perhaps the adapter (ext-base) is missing?');
            return;
        }
    
        if (!Ext.version) {
            log('Could not find version number, perhaps the adapter (ext-base) is missing?');
            return;
        }
    
        log('Ext version ' + Ext.version);
    
        if (!Ext.data || !Ext.data.Store) {
            log('Could not find Ext.data.Store, perhaps ext-all is missing?');
            return;
        }
    
        if (!Ext.BLANK_IMAGE_URL || Ext.BLANK_IMAGE_URL.indexOf('sencha.com') !== -1 || Ext.BLANK_IMAGE_URL.indexOf('extjs.com') !== -1) {
            log('Ext.BLANK_IMAGE_URL appears to be incorrectly set: ' + Ext.BLANK_IMAGE_URL);
            return;
        }
    
        log('No problems found');
    
        log('Hooking in interceptor for events');
    
        var fireEvent = Ext.util.Observable.prototype.fireEvent;
    
        Ext.util.Observable.prototype.fireEvent = function() {
            var xtype, ename = arguments[0].toLowerCase();
    
            if (this.getXType) {
                xtype = this.getXType();
            }
    
            xtype = xtype || this.id || (this.dom && this.dom.id);
    
            var msg = '<b>' + ename + '</b>' + (xtype ? ' on <b>' + xtype + '</b>' : '');
    
            if (!(this instanceof Ext.util.Observable)) {
                if (xtype) {
                    log('!! Event fired on non-observable: ' + msg);
                }
                else if (this === window) {
                    log('!! Event fired on global window object: ' + msg);
                }
                else {
                    log('!! Event fired on unknown: ' + this);
    
                    if (window['console']) {
                        console.log('!! Event fired on unknown:');
                        console.log(this);
                    }
                }
    
                return;
            }
    
            var ce = this.events[ename];
            var listenerCount = ce && ce.listeners && ce.listeners.length;
    
            if (listenerCount) {
                log('Firing event ' + msg + ': ' + listenerCount + ' listeners');
            }
    
            try {
                var retValue = fireEvent.apply(this, arguments);
    
                if (retValue === false) {
                    log('Event cancelled');
                }
    
                return retValue;
            }
            catch (ex) {
                log('!! Listener exploded: ' + msg);
                throw ex;
            }
        };
        
        // Now we've established that Ext is working...
        logShow = function() {
            if (!logWin) {
                logWin = new Ext.Window({
                    autoScroll: true,
                    closable: false,
                    height: 400,
                    title: 'Log',
                    width: 300
                });
    
                logWin.show();
    
                setInterval(function() {
                    if (logCount !== lastCount) {
                        logWin.update(Ext.util.Format.nl2br(msgs.join('\n')));
                        lastCount = logCount;
                    }
                }, 200);
    
            }
        };
    
        log('Hooking into menu rendering');
    
        var onRender = Ext.menu.Menu.prototype.onRender;
    
        Ext.menu.Menu.prototype.onRender = function() {
            log('Entering menu.onRender()');
    
            try {
                var retVal = onRender.apply(this, arguments);
                log('onRender() exited');
    
                if (this.focusEl) {
                    log('this.focusEl is ' + this.focusEl.dom.id);
                }
                else {
                    log('!! Missing this.focusEl');
                    log('Rendered HTML is: ' + Ext.util.Format.htmlEncode(this.el && this.el.dom && this.el.dom.innerHTML));
                }
    
                return retVal;
            }
            catch (ex) {
                log('onRender() threw an exception');
                throw ex;
            }
        };
    
        log('Hooking into component hiding');
    
        var hide = Ext.Component.prototype.hide;
    
        Ext.Component.prototype.hide = function() {
            log('Entering component.hide()');
    
            var xtype;
    
            if (this.getXType) {
                xtype = this.getXType();
            }
    
            xtype = xtype || this.id || (this.dom && this.dom.id);
    
            if (this === window) {
                xtype = 'global window';
            }
    
            log('hide() called on <b>' + xtype + '</b>');
    
            try {
                var retVal = hide.apply(this, arguments);
                log('hide() exited');
    
                return retVal;
            }
            catch (ex) {
                log('hide() threw an exception');
                throw ex;
            }
        };
    })();

  7. #7
    Sencha User
    Join Date
    Oct 2009
    Posts
    21
    Vote Rating
    0
    strimp099 is on a distinguished road

      0  

    Default


    Are you using any other adapters or are you just using ext-base?
    This is what I am including:
    PHP Code:
    <link rel="stylesheet" type="text/css" href="/bin/js/ext-3.2.1/resources/css/ext-all.css" />
    <
    link rel="stylesheet" type="text/css" href="/bin/js/ext-3.2.1/resources/css/xtheme-gray.css" />
    <
    link rel="stylesheet" type="text/css" href="/bin/js/ext-3.2.1/plugins/GroupHeaderPlugin.css" />
    <!-- include 
    ExtJS library files -->
    <
    script type="text/javascript" src="/bin/js/ext-3.2.1/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="/bin/js/ext-3.2.1/ext-all-debug.js"></script>
    <!-- include custom tab files -->
    <script type="text/javascript" src="/bin/js/ext-3.2.1/plugins/GroupHeaderPlugin.js"></script>
    <!-- this is the file we are working on -->
    <script type="text/javascript" src="/bin/js/dashboard/dvi.js"></script>
    <!--[if IE]><script language="javascript" type="text/javascript" src="/bin/js/jit/excanvas.js"></script><![endif]-->
    <script language="javascript" type="text/javascript" src="/bin/js/jit/jit.js"></script> 
    Are you using any patches or overrides that change classes in the Ext namespace (such things are commonly used for patching bugs)?
    No.
    You seem to have switched from ExtJS 3.2.2 to 3.2.1. Be very careful with that, ext-all and ext-base need to tie up.
    I said 3.2.2 but I am using 3.2.1 everywhere.
    That stacktrace is pretty horrific. Which debugger gave you that? I strongly recommend giving the Google Chrome debugger a try... simple stacktraces with line numbers and click through to the code.
    That was from Firebug. I'll work on getting Chrome.

    So I modified the contextMenu to include only one single item and no listeners:
    PHP Code:
    var contextMenu = new Ext.menu.Menu({
        
    items: [{
            
    text'Sort Ascending within Group'
        
    }]
    }); 
    The same two errors are occuring even though the output from your (very nice) logger only demonstrates one.
    This is the output when I click on the column header.
    Code:
    hide() exited
    Firing event hide on menu: 1 listeners
    Firing event beforehide on menu: 1 listeners
    hide() called on menu
    Entering component.hide()
    Firing event show on menu: 1 listeners
    Firing event beforeshow on menu: 1 listeners
    Firing event headerclick on grid: 2 listeners
    Firebug throws the following error which the logger does not appear to catch:
    PHP Code:
    this.focusEl is undefined // at this.setReadOnly(true); line 36159 
    When I actually click on the menu item, the following is output from your logger:
    PHP Code:
    hide() exited
    Firing event hide on menu
    1 listeners
    Firing event beforehide on menu
    1 listeners
    hide
    () called on menu
    Entering component
    .hide()
    hide() threw an exception
    hide
    () called on undefined
    Entering component
    .hide()
    Firing event show on menu1 listeners
    Firing event beforeshow on menu
    1 listeners
    Firing event headerclick on grid
    2 listeners 
    Note in each case I have to click off the menu for it to hide - it does not hide automatically.

  8. #8
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    I'll have another play with this tonight. Could you send me all the logging you get from when you first load the page till when you finally close the menu? Send it in a PM if there's a lot of it and you don't want to post it all here.

    One other question, are you using the GroupHeaderPlugin on the gird in question? Is there any way you could try removing it completely from the project (including removing the include of the JS file). Just want to rule it out, because something very odd is happening here.

  9. #9
    Sencha User
    Join Date
    Oct 2009
    Posts
    21
    Vote Rating
    0
    strimp099 is on a distinguished road

      0  

    Default


    I removed the GroupHeaderPlug reference from the project and all references to it within the grids. I still get the errors. This is the full output from the logger. The main page is a tabbed interface. The grid in question lives on one of the tabs.

    Code:
    hide() exited
    Firing event hide on menu: 1 listeners
    Firing event beforehide on menu: 1 listeners
    hide() called on menu
    Entering component.hide()
    hide() exited
    hide() called on quicktip
    Entering component.hide()
    hide() threw an exception
    hide() called on undefined
    Entering component.hide()
    Firing event show on menu: 1 listeners
    this.focusEl is ext-gen105
    onRender() exited
    Entering menu.onRender()
    Firing event beforeshow on menu: 1 listeners
    Firing event headerclick on grid: 2 listeners
    hide() exited
    hide() called on quicktip
    Entering component.hide()
    Firing event load: 1 listeners
    Firing event metachange: 1 listeners
    Firing event load: 2 listeners
    Firing event refresh: 1 listeners
    Firing event datachanged: 1 listeners
    Firing event refresh: 1 listeners
    Firing event configchange: 1 listeners
    Firing event metachange: 1 listeners
    Firing event afterlayout on toolbar: 1 listeners
    Firing event afterlayout on toolbar: 1 listeners
    Firing event beforeload: 1 listeners
    Firing event activate on dviDashboard: 1 listeners
    Firing event afterlayout on toolbar: 1 listeners
    Firing event afterlayout on toolbar: 1 listeners
    Firing event bodyresize on grid: 2 listeners
    Firing event bodyresize on dviDashboard: 1 listeners
    Firing event bodyresize on grid: 2 listeners
    Firing event afterlayout on toolbar: 1 listeners
    Firing event bodyresize on grid: 2 listeners
    Firing event resize on toolbar: 1 listeners
    Firing event render on combo: 1 listeners
    Firing event render on combo: 1 listeners
    Firing event titlechange on grid: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event add on menu: 1 listeners
    Firing event beforeshow on grid: 1 listeners
    Firing event titlechange on dviDashboard: 1 listeners
    Firing event beforeshow on dviDashboard: 1 listeners
    hide() exited
    hide() called on panel
    Entering component.hide()
    Firing event bodyresize on panel: 1 listeners
    Firing event bodyresize on tabpanel: 1 listeners
    Firing event bodyresize on panel: 1 listeners
    Firing event bodyresize on panel: 1 listeners
    Firing event bodyresize on tabpanel: 1 listeners
    Firing event titlechange on panel: 1 listeners
    Firing event beforeshow on panel: 1 listeners
    Firing event bodyresize on tabpanel: 1 listeners
    Hooking into component hiding
    Hooking into menu rendering
    Hooking in interceptor for events
    No problems found
    Ext version 3.2.1
    Verifying ExtJS
    Thanks a lot for your help on this one.

  10. #10
    Sencha User
    Join Date
    Oct 2009
    Posts
    21
    Vote Rating
    0
    strimp099 is on a distinguished road

      0  

    Default


    I just got it sorted out! I'm embarrased but it was very simple issue.

    I had the inclusion of an old version of prototype.js within the code that was conflicting with the version of prototype.js that is packaged with Ext JS.

    I kept seeing references to functions within prototype.js in the error logs from Firebug. I wen through the code with a fine-toothed-comb until I found the reference. I removed it and no errors!

    I have to say, your help and patience was incredible. I learned a great deal not only about Ext JS but debugging as well. Thank you again...

Thread Participants: 1

Tags for this Thread