这个错误在我的 JavaScript 错误日志中不断出现,在 IE 7 和 8 中。但我无法在我的生活中重现它!
“guid”为空或不是对象
我使用的是 jQuery 1.4.1,所以这不是.hover()
谷歌搜索中出现的问题。
错误发生在这里(大约行 1570 ):
if (!handler.guid) {
handler.guid = jQuery.guid++;
}
它发生的页面真的很复杂,对话框、ajax 内容、选项卡、手风琴,你能想到的,它就在那里。更糟糕的是,它是内部的,所以我不能给你们一个链接来玩它。
我无法制作小提琴 b/c 我无法重现问题:(
我知道这是一个很长的机会,当我有能力的时候,我更愿意为此提供赏金。
有没有人知道我应该寻找什么来解决这个问题?我还在使用 jquery Ui 1.8.11 和各种插件。
编辑:这是引发错误的大部分 jquery 代码。它是 jquery 事件的一部分。
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;
}
编辑:我花了大约 25 分钟试图产生这个错误,但没有运气。我正在打开和关闭标签(加载了ajax),试图让它们在加载之前改变等等。还打开和关闭对话框(加载了 ajax)并执行 ajaxly 添加和删除内容的操作。什么都不会破坏!
不确定这是否有帮助,但这是导致错误的用户代理字符串:
Mozilla/4.0(兼容;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)
这是另一个:
Mozilla/4.0(兼容;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(我们的 javascript 错误日志服务)似乎没有保留单个用户代理,所以我只有两个。
编辑:我想我已经把它缩小到我们的快速搜索。它使用 jquery ui Auto Complete 和 jquery.jail(异步图像加载)。我已经稍微调整了 jquery ui 自动完成。并且正在使用 HTML 扩展名。
这是代码:
/*
* 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 ));
在这里你可以找到监狱: https ://github.com/sebarmeli/JAIL
我尝试通过快速键入、使用鼠标和箭头、单击、按 esc、按 ctrl、tab 等各种方式来打破它。仍然没有打破。
编辑:我增加了 250 代表的赏金!一定有人遇到过这种情况。
编辑:
我刚刚看到这个错误的一个稍微不同的版本,现在来自 IE 9!无法获取属性“guid”的值:对象为空或未定义与“guid”为空或不是对象完全相同的行。
所以,要么处理程序为空,要么 jQuery 为空。我将使用处理程序,因为如果 jQuery 为空,我会有很多其他问题。
所以这意味着,我正在尝试将一个 guid 附加到一个不存在的处理程序上。这怎么可能呢?
编辑:
这是设置自动完成小部件的代码:
<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>
也许它来自 labelOver 插件(我已经改变了很多)。
这是它的代码:
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();
}
})
}
我没有看到任何明显的东西,但也许我错过了一些东西。
这是我想出的记录错误的方法:
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);
}