Frontendplace Blog

Sharing Frontend developing ideas

unspecified error in IE8 with prototype

Posted by info on November 1st, 2010

When the fireEvent method is called in the prototype.js library I sometimes get an “unspecified” error in internet explorer 8. The reason I get this error is because I have replaced some elements with an AJAX call and on these elements I have attached some eventHandlers. In IE8 somehow these replaced elements are still alive and react on events fired. If this element doesn’t exist anymore in the DOM tree the “unspecified” error is shown in IE8. The solution we have made:

  1. Cache the eventlisteners in Array
  2. Add destroy function to remove these eventlisteners from this object
  3. When an event is called check if this element has parents. if not call destroy function



We had the following code:

setListener : function(targetId, eventName){
		targetId = targetId.replace(/^#/,"");
		if (this.listeners[targetId]){
			return;
		}


		this.listeners[targetId] = true;
		var targetElement = $(targetId);
		if (!targetElement) return;

		targetElement.observe(eventName || "element:afterUpdate",function(event){
			var elementId = event.element().identify();
			if (event && targetId == elementId) {
				var url = event.memo.url;
				this.showActive(url, 1);
			}
		}.bindAsEventListener(this));
	},

and changed it to:

		var targetElement = $(targetId);
		if (!targetElement) return;

		// cache all listener data so it can be removed later on
		this.listeners[targetId] = {
			handler: function(event){
				var elementId = event.element().identify();
				if (event && targetId == elementId) {
					var url = event.memo.url;
					this.showActive(url, 1);
				}
			}.bindAsEventListener(this),
			eventName: eventName || "element:afterUpdate",
			element: targetElement
		};

		targetElement.observe(this.listeners[targetId].eventName, this.listeners[targetId].handler);

and added in the eventhandler:

		// stop if behaviour is destroyed or element is no longer part of DOM
		if (this.destroyed) return;
		if (!this.element.hasDocumentAncestor()){
			this._destroy();
			return;
		}


added this extra method:

/*
	Property: _destroy
		Destroy behaviour of this component if element is no longer part of the DOM
	*/
	_destroy : function(){
		// remove event observers
		for (var key in this.listeners){
			var listener = this.listeners[key];
			if (listener.element) listener.element.stopObserving(listener.eventName, listener.handler);
		}

		this.destroyed = true;
	}