dojo/on
and dojo/aspect
are two APIs that appear to do similar jobs but actually serve two different purposes. dojo/on
is used to setup event listeners for DOM nodes and event-emitting objects. dojo/aspect
provides Aspect Oriented Programming facilities so functionality can be run before, after, or around a method call and can even manipulate the input to the original method or the original method’s output.
dojo/on
dojo/on
is the general purpose event module and can be used to listen for events on DOM nodes and event-emitting objects. The most basic use is to set up an event listener on an element directly or to use event delegation.
require([
'dojo/on',
'dojo/query'
], function (on) {
var actionButton = document.getElementById('actionButton');
// add event listener directly to a DOM Node
on(actionButton, 'click', function () {
console.log('button clicked');
});
// use event delegation to listen for events
on(document, '.button:click', function () {
console.log('button clicked');
});
});
dojo/on
can also be used to set up listeners for events emitted from objects that inherit from dojo/Evented
. These objects gain an emit
method, which can be used to trigger a custom event.
require([
'dojo/_base/declare',
'dojo/Evented',
'dojo/on'
], function (declare, Evented, on) {
var MyClass = declare(Evented, {
run: function () {
this.emit('custom-event', { name: 'world' });
}
});
var c = new MyClass();
on(c, 'custom-event', function (data) {
console.log('hello, ' + data.name);
});
c.run();
});
dojo/aspect
On the other hand, dojo/aspect
can be used in a number of ways to run code before, after, or around a method call. For example, if we have a rand
object that has a method getNumber
which returns a random number in a given range, we can use aspect.after
to call a new method after the original method is executed and change the return value to be a little less random:
var div = document.querySelector('#result'),
after = document.querySelector('#after');
require([
'dojo/aspect'
], function (aspect) {
var rand = {
getNumber: function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
};
aspect.after(rand, 'getNumber', function (value) {
console.log('actual result ' + value);
return 4;
});
console.log('returned result ' + rand.getNumber(3, 10));
});
Similarly, we could use aspect.before
to execute code before getNumber
is called and return an array, changing the arguments that are passed to the original function:
require([
'dojo/aspect'
], function (aspect) {
var rand = {
getNumber: function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
};
aspect.before(rand, 'getNumber', function (min, max) {
console.log('original arguments: ' + min + ', ' + max);
return [6, 16];
});
console.log('returned result: ' + rand.getNumber(20, 30));
});
Finally, aspect.around
can be used to return a function to replace the original method. This new method can then conditionally call the original method if necessary:
require([
'dojo/aspect'
], function (aspect) {
var rand = {
getNumber: function (min, max) {
console.log('original method called');
return Math.floor(Math.random() * (max - min + 1)) + min;
}
};
aspect.around(rand, 'getNumber', function (origMethod) {
return function (min, max) {
if (min === max) {
console.log('not calling original method');
return min;
}
// only call the original method if min !== max
return origMethod(min, max);
};
});
console.log('returned result: ' + rand.getNumber(20, 20));
});
As you can see, dojo/on
is a useful utility for listening for events from the DOM or event-emitting objects, while dojo/aspect
is useful for injecting code before, after, or around the original method call.