Suppose shared code detects that an operation has started, but several parts of a page might need to react. Calling a global function forces the shared code and every page to agree on that function. A custom event offers a looser arrangement: announce what happened, then let interested code register its own handlers. section 13.3.2
The browser’s event-handling pattern works for application-specific occurrences too:
- Create a CustomEvent with a name such as 'ajax-start'. Put optional information in its detail property. section 13.3.2
- Call dispatchEvent on the chosen target. Other code registers handlers for that name with addEventListener. section 13.3.2
- Keep the triggering code independent of its listeners: it need not know whether there are any, or what each one does. section 13.3.2
A loading indicator without a direct UI call
An operation dispatches 'ajax-start' on document with a URL in detail, then dispatches 'ajax-complete' after a timer. Separate listeners show and hide an indicator. The timer stands in for an operation; it is not an AJAX request. section 13.3.2
Listing 13.10. Using custom events
<style>
#whirlyThing { display: none; }
</style>
<button type="button" id="clickMe">Start</button> #A
<img id="whirlyThing" src="whirly-thing.gif" /> #B
<script>
function triggerEvent(target, eventType, eventDetail){
const event = new CustomEvent(eventType, { #C
detail: eventDetail #D
});
target.dispatchEvent(event); #E
}
function performAjaxOperation() { #F
triggerEvent(document, 'ajax-start', { url: 'my-url'}); #F
setTimeout(() => { #F
triggerEvent(document, 'ajax-complete'); #F
},5000);
}
const button = document.getElementById('clickMe');
button.addEventListener('click', () => {
performAjaxOperation(); #G
});
document.addEventListener('ajax-start', e => { #H
document.getElementById('whirlyThing').style.display = 'inline-block';
assert(e.detail.url === 'my-url', 'We can pass in event data'); #I
});
document.addEventListener('ajax-complete', e => { #J
document.getElementById('whirlyThing').style.display = 'none';
});
</script>
The helper constructs a CustomEvent, supplies optional detail, and dispatches it on a target. section 13.3.2
button.addEventListener('click', () => {
performAjaxOperation();
});
document.addEventListener('ajax-start', e => {
document.getElementById('whirlyThing').style.display = 'inline-block';
assert(e.detail.url === 'my-url', 'We can pass in event data');
});
document.addEventListener('ajax-complete', e => {
document.getElementById('whirlyThing').style.display = 'none';
});
The listeners react independently; the start handler reads the URL through the event’s detail property. section 13.3.2
A compatibility caution: an application-defined CustomEvent is not the same thing as a browser-provided, browser-specific event. Being able to bind a listener does not prove that a browser will fire such an event. section 14.3.3
