Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger a custom javascript event in IE8?

I'm trying to fire a custom event on IE8 and fiddling a solution together from here and here. But I cannot get it to work...

I'm using jquery mobile with requireJS and google analytics. So I'm tracking the JQM pageshow event. However since requireJS loads scripts async, my binding to pageshow needs to be made in a javascript "wrapper", otherwise it will produce an error, because neither jquery nor jquery mobile will have been loaded by the time the snippet is parsed.

So I'm doing including this at the end of every page:

if (document.addEventListener) {
    document.addEventListener("jqmReady",function(){trigAnalytics("jqmReady");alert("FF detected")},false); 
} else if ( document.attachEvent ) {
    document.attachEvent("jqmReady", function(){trigAnalytics("jqmReady");alert("IE detected")}); 
}

And when detected, I'm firing my analytics snippet with the pageshow binding:

var trigAnalytics = function( trigger ){ 
    $(document).on('pageshow','div:jqmData(role="page").basePage', function (event, ui) {
        var url = location.href; 
        try { 
            hash = location.hash; 
            if (hash && hash.length > 1) {
                 _gaq.push(['_trackPageview', hash.substr(1)]);
                 _gaq.push(['_setCustomVar', 1, 'id_external', ########, 1 ]);
            } else {
                _gaq.push(['_trackPageview', url]);
                _gaq.push(['_setCustomVar', 1, 'id_external', ########, , 1 ]);
                _gaq.push(['b._trackPageview', url]);
            } 
        } catch(err) { } 
    }); 
    if (typeof _gaq !== "undefined" && _gaq !== null) { 
        $(document).ajaxSend(function(event, xhr, settings){ 
            _gaq.push(['_trackPageview', settings.url]); 
            _gaq.push(['b._trackPageview', settings.url]);
        }); 
    } 
}; 

So to kick of the event chain, I need to trigger jqmReady when JQM is ready. JQM uses their mobileinit event to indicate just that. So inside my application controller init, I'm binding to it like so:

$(document).bind("mobileinit", function () {

    // non-IE OK
    if (document.createEvent) {
        evt = document.createEvent("Event");
        evt.initEvent("jqmReady", true, true);
        document.dispatchEvent(evt);

    } else if (document.createEventObject) { 
    // MSIE (NOT WORKING)

        document.documentElement.evt = 0; // an expando property
        document.documentElement.attachEvent("jqmReady", function () {
            document.documentElement.evt = document.documentElement.evt + 1;
            });
    }
});

I have tried just triggering $(window).trigger('jqmReady'), because when mobileinit triggers, jquery is available. However it seems events created in addEventListener can not be triggered like this, so I need a javascript-only solution to trigger a custom event in IE.

Question:
Can someone give me a pointer on how to trigger a javascript custom event for IE8 correctly?

like image 696
frequent Avatar asked Nov 17 '12 21:11

frequent


People also ask

What is trigger in Javascript?

Definition and Usage. The trigger() method triggers the specified event and the default behavior of an event (like form submission) for the selected elements. This method is similar to the triggerHandler() method, except that triggerHandler() does not trigger the default behavior of the event.

What is dispatch event in Javascript?

The dispatchEvent() method of the EventTarget sends an Event to the object, (synchronously) invoking the affected EventListener s in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent() .


2 Answers

Ok, I finally understand... here is how it works:

1) setting the listener for jqmReady on the page being loaded

// non-IE: just create a listener for the custom event "jqmReady"
if (document.addEventListener) {
    document.addEventListener("jqmReady",function(){trigAnalytics("jqmReady");alert("FF detected")},false); 
// IE8
} else if ( document.attachEvent ) {

    // create a custom property name jqmReady and set it to 0
    document.documentElement.jqmReady = 0;
    // since IE8 does not allow to listen to custom events, 
    // just listen to onpropertychange
    document.documentElement.attachEvent("onpropertychange", function(event) {

        // if the property changed is the custom jqmReady property
        if (event.propertyName == "jqmReady") {
            trigAnalytics("jqmReady");
            alert("gotcha")
            // remove listener, since it's only used once
            document.documentElement.detachEvent("onpropertychange", arguments.callee);
        }
    });
}

So on IE8 I'm not listening for custom jqmReady. Instead I listen for onpropertychange for my custom property jqmReady

2) Then on mobileinit I'm triggering like this:

 // non-IE
 if (document.createEvent) {
      evt = document.createEvent("Event");
      evt.initEvent("jqmReady", true, true);
      document.dispatchEvent(evt);
 } else if (document.createEventObject) { // MSIE
      // just change the property 
      // this will trigger onpropertychange
      document.documentElement.jqmReady++;
 };

Nice idea (credit to http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/), maybe someone else can find a use for it.

like image 119
frequent Avatar answered Sep 18 '22 12:09

frequent


For anyone else interested, I've wrapped up this code into a static javascript object

function Event () {
}

Event.listen = function (eventName, callback) {
    if(document.addEventListener) {
        document.addEventListener(eventName, callback, false);
    } else {    
        document.documentElement.attachEvent('onpropertychange', function (e) {
            if(e.propertyName  == eventName) {
                callback();
            }            
        });
    }
}

Event.trigger = function (eventName) {
    if(document.createEvent) {
        var event = document.createEvent('Event');
        event.initEvent(eventName, true, true);
        document.dispatchEvent(event);
    } else {
        document.documentElement[eventName]++;
    }
}

usage:

Event.listen('myevent', function () {
    alert('myevent triggered!');
});

Event.trigger('myevent');

Demo: http://jsfiddle.net/c5CuF/

like image 40
Elliott Avatar answered Sep 21 '22 12:09

Elliott