Event injection and boiling
New in v1.4
The Infusion Event System explains how to declare events of various types attached to a single component. Within a larger design, sometimes it is necessary to
collaborate between multiple components in a component tree on "sharing" references to event firers ("event injection")
present an event with a particular signature fired by a component as one with a different signature in a listener ("event boiling")
Both of these capabilities rely on the Inversion of Control (IoC) system and on the tree of components in question being an IoC-driven tree.
Event injection
Event injection comes in two different forms. The first form is the wholesale injection of an event belonging to one component, to appear as an event belonging to another. These events will share a single set of listeners which will be fired when any sharing component fires the event, and any sharing component may add and remove listeners. This is achieved by simply referencing the source event to be injected on the right hand side of the standard events block on the component. For example:
Proper scoping for event binding
Note that the defaults we have written here for childComponent reflect a bad practice - a "blind reference" to a parent component which may or may not actually be in scope when the child is instantiated. This form of definition was just written for clarity here, but in fact prevents the childComponent component from being used in contexts where it could not find parentComponent. A sounder way of expressing this relationship is to write the injection of parentEvent in a demands block which is scoped so that it only binds in a context where parentComponent component is actually present. This would be done with the following pair of definitions:
Event boiling
A "Boiled" event is derived from another event (a "base event") but allows the signature of the event to be adjusted. A listener to a boiled event receives a call at the same point in time, but can receive a different set of arguments than the ones which were supplied in the original call to fire() which triggered the event. This modified argument set can draw values from IoC-resolved contextual values around the component tree, as well as from the original argument set which the firer of the event supplied.
Boiled events are useful in wiring together consumers and producers of events who have different expectations - these differences can arise, for example, through the development of the codebases being in different lifecycles - perhaps the producer of the event is part of framework code which is not going to be updated for a long time, but has been written with a poorly planned API which does not expose crucial information which the event consumer requires.
Suggestions are still welcomed for more a suitable name than "boiled events".
Boiling in defaults
A boiled event is defined in just the same place as a standard event - in the "events" block of a component's defaults. The configuration ("right-hand side") value is more complex than that for a simple event - it needs to specify not only the base event, but also the transformation performed on the argument list. The configured value must contain two elements, the event property, which references the event to be boiled, and the args which specifies the argument list which will be received by listeners to the boiled event. This uses the standard {context}.pathName format for contextualised EL values which is used in IoC, with the addition that one extra context object is in scope - the context {arguments} allows the argument list to refer to the original argument list that was presented when the base event was fired. For example:
fluid.defaults("fluid.tests.eventBoiled", {
gradeNames: ["fluid.eventedComponent", "autoInit"],
events: {
boiledLocal: {
event: "localEvent",
args: ["{arguments}.1", "{arguments}.0"]
},
localEvent: null
}
});
In this code block, the component defines two events - one "basic event" named localEvent, and one "boiled event" named boiledLocal which uses localEvent as a base. In this case, a listener registered to boiledLocal will receive the first two arguments which were supplied when localEvent was fired, but swapped to appear in the opposite order.
Boiling in demands
The boiling specification for an event may also appear in a demands block rather than in a component's defaults. This caters for the case that different signatures are required for events fired from the same component where it appears in different contexts.
fluid.defaults("fluid.tests.eventBoiled", {
gradeNames: ["fluid.eventedComponent", "autoInit"],
events: {
boiledLocal: {
event: "localEvent"
},
localEvent: null
});
fluid.demands("boiledLocal", "fluid.tests.eventBoiled",
["{arguments}.0", "{arguments}.1"]);
It's necessary to supply some specification in the parent that the event will be boiled - in particular, the base event that it derives from. However, the actual argument specification can be deferred to the demands block, using the standard syntax for arguments in demands blocks.