Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery "guid" is null or not an object

This error keeps coming up in my JavaScript error logging, In IE 7 and 8. But I can't reproduce it for the life in me!

"guid" is null or not an object

I'm using jQuery 1.4.1 so it's not the .hover() problem that comes up in google searches.

the error is happening here (around line 1570 ):

  if (!handler.guid) {
        handler.guid = jQuery.guid++;
  }

The page it's happening on is really really complex, dialogs, ajax content, tabs, accordions, you name it, it's on there. and worse, it's internal, so I can't give you guys a link to play with it.

I can't make a fiddle b/c I can't reproduce the problem :(

I know this is a long shot, and I'm more then willing to put up a bounty for this when I am able to.

Does anyone have any ideas of what I should be looking for to solve this? I'm also using jquery Ui 1.8.11 and a variety of plugins.

Edit: Here is the larger part of the jquery code that is throwing the error. it's part of jquery's event stuff.

add: function (elem, types, handler, data) {
            if (elem.nodeType === 3 || elem.nodeType === 8) {
                return;
            }

            // For whatever reason, IE has trouble passing the window object
            // around, causing it to be cloned in the process
            if (elem.setInterval && (elem !== window && !elem.frameElement)) {
                elem = window;
            }

            // Make sure that the function being executed has a unique ID
            if (!handler.guid) {
                handler.guid = jQuery.guid++;
            }

            // if data is passed, bind to handler
            if (data !== undefined) {
                // Create temporary function pointer to original handler
                var fn = handler;

                // Create unique handler function, wrapped around original handler
                handler = jQuery.proxy(fn);

                // Store data in unique handler
                handler.data = data;
            }

            // Init the element's event structure
            var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
            handle = jQuery.data(elem, "handle"), eventHandle;

            if (!handle) {
                eventHandle = function () {
                    // Handle the second event of a trigger and when
                    // an event is called after a page has unloaded
                    return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
                    jQuery.event.handle.apply(eventHandle.elem, arguments) :
                    undefined;
                };

                handle = jQuery.data(elem, "handle", eventHandle);
            }

            // If no handle is found then we must be trying to bind to one of the
            // banned noData elements
            if (!handle) {
                return;
            }

            // Add elem as a property of the handle function
            // This is to prevent a memory leak with non-native
            // event in IE.
            handle.elem = elem;

            // Handle multiple events separated by a space
            // jQuery(...).bind("mouseover mouseout", fn);
            types = types.split(/\s+/);

            var type, i = 0;

            while ((type = types[i++])) {
                // Namespaced event handlers
                var namespaces = type.split(".");
                type = namespaces.shift();

                if (i > 1) {
                    handler = jQuery.proxy(handler);

                    if (data !== undefined) {
                        handler.data = data;
                    }
                }

                handler.type = namespaces.slice(0).sort().join(".");

                // Get the current list of functions bound to this event
                var handlers = events[type],
                special = this.special[type] || {};

                // Init the event handler queue
                if (!handlers) {
                    handlers = events[type] = {};

                    // Check for a special event handler
                    // Only use addEventListener/attachEvent if the special
                    // events handler returns false
                    if (!special.setup || special.setup.call(elem, data, namespaces, handler) === false) {
                        // Bind the global event handler to the element
                        if (elem.addEventListener) {
                            elem.addEventListener(type, handle, false);
                        } else if (elem.attachEvent) {
                            elem.attachEvent("on" + type, handle);
                        }
                    }
                }

                if (special.add) {
                    var modifiedHandler = special.add.call(elem, handler, data, namespaces, handlers);
                    if (modifiedHandler && jQuery.isFunction(modifiedHandler)) {
                        modifiedHandler.guid = modifiedHandler.guid || handler.guid;
                        modifiedHandler.data = modifiedHandler.data || handler.data;
                        modifiedHandler.type = modifiedHandler.type || handler.type;
                        handler = modifiedHandler;
                    }
                }

                // Add the function to the element's handler list
                handlers[handler.guid] = handler;

                // Keep track of which events have been used, for global triggering
                this.global[type] = true;
            }

            // Nullify elem to prevent memory leaks in IE
            elem = null;
        }

EDIT: I spent about 25 minutes trying to produce this error with no luck. I was opening and closing tabs(ajax loaded), trying to get them to change before the loaded and whatnot. also opening and closing dialogs (ajax loaded) and doing things that added and removed content ajaxly. nothing would break!

Not sure if this is helpful, but here is a user agent string that is causing the error:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB7.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)

and here is another:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC LM 8; MS-RTC LM 8)

errorception (our javascript error logging service) doesn't seem to keep individual user agents, so i only have the two.

EDIT: I think i've narrowed it down to our quick search. which uses jquery ui Auto Complete, and jquery.jail (async image loading). I have tweaked jquery ui auto complete a bit. and am using the HTML extension.

Here is the code:

    /*
     * jQuery UI Autocomplete 1.8.11
     *
     * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
     * Dual licensed under the MIT or GPL Version 2 licenses.
     * http://jquery.org/license
     *
     * http://docs.jquery.com/UI/Autocomplete
     *
     * Depends:
     *  jquery.ui.core.js
     *  jquery.ui.widget.js
     *  jquery.ui.position.js

 */

(function( $, undefined ) {

// used to prevent race conditions with remote data sources
var requestIndex = 0;

$.widget( "ui.autocomplete", {
    options: {
        appendTo: "body",
        autoFocus: false,
        delay: 300,
        minLength: 1,
        position: {
            my: "left top",
            at: "left bottom",
            collision: "none"
        },
        source: null
    },

    pending: 0,

    _create: function() {
        var self = this,
            doc = this.element[ 0 ].ownerDocument,
            suppressKeyPress;

        this.element
            .addClass( "ui-autocomplete-input" )
            .attr( "autocomplete", "off" )
            // TODO verify these actually work as intended
            .attr({
                role: "textbox",
                "aria-autocomplete": "list",
                "aria-haspopup": "true"
            })
            .bind( "keydown.autocomplete", function( event ) {
                if ( self.options.disabled || self.element.attr( "readonly" ) ) {
                    return;
                }

                suppressKeyPress = false;
                var keyCode = $.ui.keyCode;
                switch( event.keyCode ) {
                case keyCode.PAGE_UP:
                    self._move( "previousPage", event );
                    break;
                case keyCode.PAGE_DOWN:
                    self._move( "nextPage", event );
                    break;
                case keyCode.UP:
                    self._move( "previous", event );
                    // prevent moving cursor to beginning of text field in some browsers
                    event.preventDefault();
                    break;
                case keyCode.DOWN:
                    self._move( "next", event );
                    // prevent moving cursor to end of text field in some browsers
                    event.preventDefault();
                    break;
                case keyCode.ENTER:
                case keyCode.NUMPAD_ENTER:
                    // when menu is open and has focus
                    if ( self.menu.active ) {
                        // #6055 - Opera still allows the keypress to occur
                        // which causes forms to submit
                        suppressKeyPress = true;
                        event.preventDefault();
                    }
                    //passthrough - ENTER and TAB both select the current element
                case keyCode.TAB:
                    if ( !self.menu.active ) {
                        return;
                    }
                    self.menu.select( event );
                    break;
                case keyCode.ESCAPE:

                    //This is changed by ME!   added self.term = ''; and also self.element.blur();  //this was so that when you hit esc, it clears the box, and puts it back to an empty state.

                    self.term = '';
                    self.element.val( self.term );
                    self.close( event );
                    self.element.blur();
                    break;
                default:
                    // keypress is triggered before the input value is changed
                    clearTimeout( self.searching );
                    self.searching = setTimeout(function() {
                        // only search if the value has changed
                        if ( self.term != self.element.val() ) {
                            self.selectedItem = null;
                            self.search( null, event );
                        }
                    }, self.options.delay );
                    break;
                }
            })
            .bind( "keypress.autocomplete", function( event ) {
                if ( suppressKeyPress ) {
                    suppressKeyPress = false;
                    event.preventDefault();
                }
            })
            .bind( "focus.autocomplete", function() {
                if ( self.options.disabled ) {
                    return;
                }

                self.selectedItem = null;
                self.previous = self.element.val();
            })
            .bind( "blur.autocomplete", function( event ) {
                if ( self.options.disabled ) {
                    return;
                }

                clearTimeout( self.searching );
                // clicks on the menu (or a button to trigger a search) will cause a blur event
                self.closing = setTimeout(function() {
                    self.close( event );
                    self._change( event );
                }, 150 );
            });
        this._initSource();
        this.response = function() {
            return self._response.apply( self, arguments );
        };
        this.menu = $( "<ul></ul>" )
            .addClass( "ui-autocomplete" )
            .appendTo( $( this.options.appendTo || "body", doc )[0] )
            // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
            .mousedown(function( event ) {
                // clicking on the scrollbar causes focus to shift to the body
                // but we can't detect a mouseup or a click immediately afterward
                // so we have to track the next mousedown and close the menu if
                // the user clicks somewhere outside of the autocomplete
                var menuElement = self.menu.element[ 0 ];
                if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
                    setTimeout(function() {
                        $( document ).one( 'mousedown', function( event ) {
                            if ( event.target !== self.element[ 0 ] &&
                                event.target !== menuElement &&
                                !$.ui.contains( menuElement, event.target ) ) {
                                self.close();
                            }
                        });
                    }, 1 );
                }

                // use another timeout to make sure the blur-event-handler on the input was already triggered
                setTimeout(function() {
                    clearTimeout( self.closing );
                }, 13);
            })
            .menu({
                focus: function( event, ui ) {
                    var item = ui.item.data( "item.autocomplete" );
                    if ( false !== self._trigger( "focus", event, { item: item } ) ) {
                        // use value to match what will end up in the input, if it was a key event
                        if ( /^key/.test(event.originalEvent.type) ) {
                            //self.element.val( item.value );       //changed by me, if they use the keys, don't change the text! don't want a textbox with a number in it.

                        }
                    }
                },
                selected: function( event, ui ) {
                    var item = ui.item.data( "item.autocomplete" ),
                        previous = self.previous;

                    // only trigger when focus was lost (click on menu)
                    if ( self.element[0] !== doc.activeElement ) {
                        self.element.focus();
                        self.previous = previous;
                        // #6109 - IE triggers two focus events and the second
                        // is asynchronous, so we need to reset the previous
                        // term synchronously and asynchronously :-(
                        setTimeout(function() {
                            self.previous = previous;
                            self.selectedItem = item;
                        }, 1);
                    }

                    if ( false !== self._trigger( "select", event, { item: item } ) ) {
                        self.element.val( item.value );
                    }
                    // reset the term after the select event
                    // this allows custom select handling to work properly
                    self.term = self.element.val();

                    self.close( event );
                    self.selectedItem = item;
                },
                blur: function( event, ui ) {
                    // don't set the value of the text field if it's already correct
                    // this prevents moving the cursor unnecessarily
                    if ( self.menu.element.is(":visible") &&
                        ( self.element.val() !== self.term ) ) {
                        self.element.val( self.term );
                    }
                }
            })
            .zIndex( this.element.zIndex() + 1 )
            // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
            .css({ top: 0, left: 0 })
            .hide()
            .data( "menu" );
        if ( $.fn.bgiframe ) {
             this.menu.element.bgiframe();
        }
    },

    destroy: function() {
        this.element
            .removeClass( "ui-autocomplete-input" )
            .removeAttr( "autocomplete" )
            .removeAttr( "role" )
            .removeAttr( "aria-autocomplete" )
            .removeAttr( "aria-haspopup" );
        this.menu.element.remove();
        $.Widget.prototype.destroy.call( this );
    },

    _setOption: function( key, value ) {
        $.Widget.prototype._setOption.apply( this, arguments );
        if ( key === "source" ) {
            this._initSource();
        }
        if ( key === "appendTo" ) {
            this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
        }
        if ( key === "disabled" && value && this.xhr ) {
            this.xhr.abort();
        }
    },

    _initSource: function() {
        var self = this,
            array,
            url;
        if ( $.isArray(this.options.source) ) {
            array = this.options.source;
            this.source = function( request, response ) {
                response( $.ui.autocomplete.filter(array, request.term) );
            };
        } else if ( typeof this.options.source === "string" ) {
            url = this.options.source;
            this.source = function( request, response ) {
                if ( self.xhr ) {
                    //added try catch
                    try{
                        if(self.xhr.abort != null){ 
                            self.xhr.abort();
                        }
                    }
                    catch(err){

                    }

                    delete self.xhr;

                }

                self.xhr = $.ajax({
                    url: url,
                    data: request,
                    dataType: "json",
                    autocompleteRequest: ++requestIndex,
                    success: function( data, status ) {
                        if ( this.autocompleteRequest === requestIndex ) {
                            response( data );
                        }
                    },
                    error: function() {
                        if ( this.autocompleteRequest === requestIndex ) {
                            response( [] );
                        }
                    }
                });
            };
        } else {
            this.source = this.options.source;
        }
    },

    search: function( value, event ) {
        value = value != null ? value : this.element.val();

        // always save the actual value, not the one passed as an argument
        this.term = this.element.val();

        if ( value.length < this.options.minLength ) {
            return this.close( event );
        }

        clearTimeout( this.closing );
        if ( this._trigger( "search", event ) === false ) {
            return;
        }

        return this._search( value );
    },

    _search: function( value ) {
        this.pending++;
        this.element.addClass( "ui-autocomplete-loading" );

        this.source( { term: value }, this.response );
    },

    _response: function( content ) {
        if ( !this.options.disabled && content && content.length ) {
            content = this._normalize( content );
            this._suggest( content );
            this._trigger( "open" );
        } else {
            this.close();
        }
        this.pending--;
        if ( !this.pending ) {
            this.element.removeClass( "ui-autocomplete-loading" );
        }
    },

    close: function( event ) {
        clearTimeout( this.closing );
        if ( this.menu.element.is(":visible") ) {
            this.menu.element.hide();
            this.menu.deactivate();
            this._trigger( "close", event );
        }
    },

    _change: function( event ) {
        if ( this.previous !== this.element.val() ) {
            this._trigger( "change", event, { item: this.selectedItem } );
        }
    },

    _normalize: function( items ) {
        // assume all items have the right format when the first item is complete
        if ( items.length && items[0].label && items[0].value ) {
            return items;
        }
        return $.map( items, function(item) {
            if ( typeof item === "string" ) {
                return {
                    label: item,
                    value: item
                };
            }
            return $.extend({
                label: item.label || item.value,
                value: item.value || item.label
            }, item );
        });
    },

    _suggest: function( items ) {
        var ul = this.menu.element
            .empty()
            .zIndex( this.element.zIndex() + 1 );
        this._renderMenu( ul, items );
        // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
        this.menu.deactivate();
        this.menu.refresh();

        // size and position menu
        ul.show();
        this._resizeMenu();
        ul.position( $.extend({
            of: this.element
        }, this.options.position ));

        if ( this.options.autoFocus ) {
            this.menu.next( new $.Event("mouseover") );
        }
    },

    _resizeMenu: function() {
        var ul = this.menu.element;
        ul.outerWidth( Math.max(
            ul.width( "" ).outerWidth(),
            this.element.outerWidth()
        ) );
    },

    _renderMenu: function( ul, items ) {
        var self = this;
        $.each( items, function( index, item ) {
            self._renderItem( ul, item );
        });
    },

    _renderItem: function( ul, item) {
        return $( "<li></li>" )
            .data( "item.autocomplete", item )
            .append( $( "<a></a>" ).text( item.label ) )
            .appendTo( ul );
    },

    _move: function( direction, event ) {
        if ( !this.menu.element.is(":visible") ) {
            this.search( null, event );
            return;
        }
        if ( this.menu.first() && /^previous/.test(direction) ||
                this.menu.last() && /^next/.test(direction) ) {
            this.element.val( this.term );
            this.menu.deactivate();
            return;
        }
        this.menu[ direction ]( event );
    },

    widget: function() {
        return this.menu.element;
    }
    });

    $.extend( $.ui.autocomplete, {
        escapeRegex: function( value ) {
            return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
        },
        filter: function(array, term) {
            var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
            return $.grep( array, function(value) {
                return matcher.test( value.label || value.value || value );
            });
        }
    });

    }( jQuery ));

the html extension: https://github.com/scottgonzalez/jquery-ui-extensions/blob/e34c9457619a13a01774f7954175320ac1e283c1/autocomplete/jquery.ui.autocomplete.html.js

and here is where you can find JAIL: https://github.com/sebarmeli/JAIL

I tried breaking it by typing fast, using the mouse and arrows, clicking around, hitting esc, hiting ctrl, tab, all sorts of things. still doesn't break.

Edit: I've added a 250 rep bounty! There has to be someone out there who has come across this.

EDIT:

I've just seen a slightly different version of this error, now from IE 9! Unable to get value of the property "guid": object is null or undefined exact same line as the "guid" is null or not an object.

so, either handler is null, or jQuery is null. i'm going to go with handler, since if jQuery was null, i'd have a lot of other problems.

so this means, i'm trying to attach a guid, to a handler that doesn't exist. how could that even be possible?

Edit:

Here is the code that is setting up the auto complete widget:

<div class="watermarkText" >
    <label for="UserLookUp" class="over" id="UserLookUpLable"  ><%= Web.QuickSearchGhostText.HtmlEncode%></label>
    <input type="text" id="UserLookUp" name="UserLookUp" style="width:250px;vertical-align:middle;" />
</div>

<img src="ClearLookUp.jpg" alt="Clear Text" id="ClearLookUp"  />

<script type="text/javascript">

    $(function () {
        $("#UserLookUp").autocomplete({
            source: 'aurl',
            minLength: 2,
            delay: 2,
            autoFocus: true,
            html: true,
            select: function (event, ui) {
                window.location = "a url".replace("0", ui.item.value);
                return false;
            },
            open: function (event, ui) {

                $('img.LookUpControlPicture').jail();
            }
        });

        $('#UserLookUpLable').labelOver('over');

        $('#ClearLookUp').click(function () {
            $('#UserLookUp').val('');
            $('#UserLookUp').autocomplete("search");
            $('#UserLookUp').blur();
        });
    });

</script>

Maybe it's coming from the labelOver plugin (which i have changed, a lot).

Here's the code for it:

jQuery.fn.labelOver = function (overClass) {
    ///<summary> 
    ///    applied to the label(s) to be ghosted over a textbox.  
    //     generally used like so: $('.watermarkText').find('label').labelOver('over'); 
    ///</summary>
    ///<param name="overClass" type="string">the class to apply to the label to style it as ghosted text.</param>
    ///<returns>nothing</returns>

    return this.each(function () {
        var label = jQuery(this);
        var f = label.attr('for');
        if (f) {
            var input = jQuery('#' + f);

            this.hide = function () {
                // label.css({ textIndent: -10000 })
                label.css('visibility', 'hidden');
            }

            this.show = function () {
                if (input.val() == '') label.css('visibility', 'visible');     //{ textIndent: 0 }
            }

            // handlers
            input.focus(this.hide);
            input.blur(this.show);

            //added by me
            input.change(function () {
                if (input.val() == '') {
                    label.css('visibility', 'visible');
                }
                else {
                    label.css('visibility', 'hidden');
                }
            });
            label.addClass(overClass).click(function () { input.focus() });

            if (input.val() != '') this.hide();
        }
    })
}

I don't see anything really obvious, but maybe i'm missing something.

Here is what i've come up with to log the error:

try {
    if (!handler.guid) {
          handler.guid = jQuery.guid++;
    }
}
catch (err) {
                var message = "handler.guid = jQuery.guid++ Error! \n";
                message += 'types: ' + types + '\n';
                if (typeof data != 'undefined') {
                    if (typeof data == 'object') {

                        $.each(data, function (i, v) {
                            message += i + ' : ' + v + '\n';
                        });
                    }
                    else {
                        message += 'elem id:' + $(elem).attr('id') + 'elem class: ' + $(elem).attr('class');
                    }
                }
                else {
                    message += 'data is undefined';
                }

                var url = window.location.href;
                var linenumber = 1579;
                v2LogTheErrorToElmah(message, url, linenumber, 0);

   }
like image 675
Patricia Avatar asked Jul 04 '12 14:07

Patricia


3 Answers

It seems very likely that the problem is an incorrect event handler, since:

$('body').click(1);

reproduces that exact error in IE. However, without seeing all of your code, there's no way to find the specific error.

What I'd recommend trying instead is that you modify the jQuery code (temporarily) to add the following line:

if (typeof handler != 'function') {alert(handler); alert(type); alert(data); alert(this);}

(and maybe add some more alerts if those aren't enough).

That should go inside jQuery.each(["bind", "one"], function( i, name ) {, after all the argument parsing but just before the line var handler = name === "one" ? jQuery.proxy( fn, function( event ) {. This is line 2324 for me, but it might be different for you.

Once you've added that line you should be able to use your site, and when you make the bad event hookup (before the error ever occurs) you should get a barrage of alerts that (hopefully) tell you what's going wrong.

Or, worst case scenario, if you try this and can't find any bad event hookups, at least you'll be able to rule that out as a possible cause of the problem.

like image 81
machineghost Avatar answered Sep 20 '22 08:09

machineghost


How about just patching your version of jQuery:

if (!handler.guid) {
  handler.guid = jQuery.guid = (jQuery.guid||0) + 1;
}

The code is equivalent, but yet more compatible with IE7. I recommend trying to reproduce the problem first, if you can. But this should prevent it from happening in the future.

like image 25
redolent Avatar answered Sep 22 '22 08:09

redolent


Quick possibility and something I check for when I get odd errors like this is to make sure jQuery isn't being included multiple times.

If you try what machineghost suggested (modifying jQuery source) and you find that it's not logging, or it stops logging at a certain point that'll be a giveaway. Or just look at your http requests in Firebug/Chrome's network profiler ;)


Some rationale: sometimes these things will end up pulling in dependencies. For example, if you append a fragment of markup that contains a <script src="some_other_jquery"></script>.

It's odd for a global property on the jQuery object to be set to null or otherwise removed.

The next time you reproduce the error you'll want to inspect the jQuery object a bit. Check jQuery.guid (should be null, but just confirm for yourself). jQuery.fn.jquery will give you the version number of your jQuery library.


Just browsed the comments and saw that you've checked for this.

like image 31
Koobz Avatar answered Sep 22 '22 08:09

Koobz