views:

283

answers:

1

I need to fire a one time only custom event that functions like the domready event, in that if new events are added after the event has occurred they are fired immediately.

This is for some code that cannot execute until certain data and resources are initialized, so I want to do something like this:

// I am including a script (loadResources.js) to load data and other resources,
// when loadResources.js is done doing it's thing it will fire resourcesAreLoaded with:
window.fireEvent('resourcesAreLoaded');

window.addEvent('resourcesAreLoaded', function() {
    // this is fine 
});
$('mybutton').addEvent('click', function() {
    window.addEvent('resourcesAreLoaded', function() {
        // this is not fine, because resourcesAreLoaded has already fired
        // by the time the button is clicked
    });
});

If possible I would like resourcesAreLoaded to function like domready, and execute the code immediately if the event has already fired:

window.addEvent('testIsReady', function() {
    alert('firing test');       
});
window.fireEvent('testIsReady');
window.addEvent('test', function() {
    // this will never execute unless I call fireEvent('testIsReady') again
    alert('test 2');        
});

window.addEvent('domready', function() {
    alert('domready is firing');        
});

window.addEvent('domready', function() {
    setTimeout(function() {
        alert('domready has already fired, so this is executed immediately');       
    }, 500);
});
+1  A: 

You would have to store the state of whether the custom event has been fired somewhere. One good place is the Element Store.

Custom events can have various properties defined. One useful property for this case is onAdd which is basically a function that is called when you add that event to some DOM element by calling <element>.addEvent(<name>, <fn>). Your function for onAdd will be called, and passed fn as a parameter. Check if the event has already been fired, and if so, call fn immediately, otherwise do nothing. Read up more about properties for custom events under the Hash: Element.Events section towards the bottom.

Element.Events.resourcesLoaded = {
    onAdd: function(fn) {
        if(window.retrieve('resourcesLoaded')) {
            fn.call(this);
        }
    }
};

When you first fire the resourcesLoaded event, also set a boolean property for the window object. onAdd can pull up this value from now on to see if event handlers should be fired immediately.

window.fireEvent('resourcesLoaded');
window.store('resourcesLoaded', true);

That should do it. Here are two test scenarios:

  1. Resources have not been loaded, so the callback should not fire immediately.

    window.addEvent('resourcesLoaded', function() { alert("should wait"); });

  2. Resources have been loaded, so the callback fires immediately.

    window.addEvent('resourcesLoaded', function() { alert("shouldn't wait"); });

I took this from the MooTools source code. This is how it handles the domready event.

On a side note, it's equally easy to implement events inside your own custom objects and you don't have to rely on DOM elements such as window to do the job if the event has nothing to do with the DOM.

Anurag
+1, good answer
Dimitar Christoff
thanks @Dimitar
Anurag