このエラーは、IE 7および8のJavaScriptエラーログに表示され続けます。しかし、私はそれを一生再現することはできません。
「GUID」がnullであるか、オブジェクトではありません
私はjQuery1.4.1を使用しているので.hover()
、グーグル検索で発生する問題ではありません。
ここでエラーが発生しています(1570行目あたり):
if (!handler.guid) {
handler.guid = jQuery.guid++;
}
それが起こっているページは本当に本当に複雑です、ダイアログ、ajaxコンテンツ、タブ、アコーディオン、あなたはそれを名付けます、それはそこにあります。さらに悪いことに、それは内部的なものなので、皆さんにそれで遊ぶためのリンクを与えることはできません。
私はフィドルを作ることができませんb/c私は問題を再現することができません:(
私はこれがロングショットであることを知っています、そして私がそうすることができるとき、私はこれのために賞金をあげることをいとわないです。
これを解決するために私が何を探すべきかについて誰かが何か考えを持っていますか?また、jqueryUi1.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エラーログサービス)は個々のユーザーエージェントを保持していないようですので、私は2つしか持っていません。
編集:私はそれを私たちのクイック検索に絞り込んだと思います。これは、jquery uiオートコンプリートとjquery.jail(非同期画像読み込み)を使用します。jqueryuiのオートコンプリートを少し調整しました。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 ));
ここにJAILがあります: https ://github.com/sebarmeli/JAIL
私は、マウスと矢印を使用して、高速で入力し、クリックし、escを押し、ctrl、tabを押して、さまざまなことでそれを壊してみました。まだ壊れません。
編集:250 repの報奨金を追加しました!これに出くわした誰かがそこにいる必要があります。
編集:
このエラーのわずかに異なるバージョンがIE9から表示されました。プロパティ「guid」の値を取得できません:オブジェクトがnullであるか、「guid」がnullであるか、オブジェクトではないのとまったく同じ行が未定義です。
したがって、ハンドラーがnullであるか、jQueryがnullです。jQueryがnullの場合、他にも多くの問題が発生するため、ハンドラーを使用します。
つまり、存在しないハンドラーに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);
}