11

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?

Community
  • 1
  • 1
frequent
  • 27,643
  • 59
  • 181
  • 333
  • why not place that trigger in $(document).ready() ? why you can need that at all ? – zb' Nov 17 '12 at 23:24
  • Because `jquery` ~ $(document).ready() will not be available when this code runs. The snippet is on the page right after the requireJS initialization. So the (1) page is parsed, (2) requireJS triggers, (3) my snippet executes. When it does, neither `jquery` or `jquery-mobile` will have fully loaded. So, must be javascript-only. – frequent Nov 18 '12 at 10:02
  • I'm not sure I follow your question (hence comment, not answer) but is [`dispatchEvent()`](https://developer.mozilla.org/en-US/docs/DOM/element.dispatchEvent) of relevance? – David Thomas Nov 18 '12 at 11:10
  • Which part is not clear? Bottom line is I need to find a way to trigger a custom event in javascript only, which works on IE8. Let me check `dispatchEvent`. – frequent Nov 18 '12 at 11:14
  • @frequent, ah lol jquery mobile.... http://jquerymobile.com/test/docs/api/events.html **Important: Use $(document).bind('pageinit'), not $(document).ready()** – zb' Nov 18 '12 at 11:18
  • @eicto: :-) (and 4 characters) – frequent Nov 18 '12 at 11:20
  • @DavidThomas: From what I understand `dispatchEvent` cannot be used for custom events, such as my `jqmReady` event. – frequent Nov 18 '12 at 11:35

2 Answers2

12

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.

frequent
  • 27,643
  • 59
  • 181
  • 333
  • 2
    One downside to `onpropertychange` is that it doesn't bubble though. You have to know in advance which element has its property changed. More info at http://msdn.microsoft.com/en-us/library/ie/ms536956%28v=vs.85%29.aspx – dotnetCarpenter Nov 25 '13 at 09:13
6

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/

bluesmoon
  • 3,918
  • 3
  • 25
  • 30
Elliott
  • 2,669
  • 2
  • 23
  • 33