Controlling when update() shall be called
Understand Bricks explains the default behavior of bricks, and when the code you write in update()
and render()
is called. Let's now go a bit deeper to understand how you can override the brick's setupExecution()
method to control when those method shall be called.
The code of all core Olympe bricks is available on GitHub.
Here are the default behavior of bricks, and sample reasons for changing the behavior:
DRAW | Base class in CODE | Default behavior | Some reasons to override setupExecution() | Examples |
---|---|---|---|---|
Functions | Brick | By default, update() is called once every input has been initialised, and then everytime one of the inputs is updated. | Execute the brick even if some inputs have not yet been initialized. | The If brick. |
Actions | ActionBrick | By default, update() is called when the control flow is triggered. | When there is more than one control flow. | The Control Flow Multiplexer brick. |
Visual components | VisualBrick or ReactBrick | By default, render() is called when the component is loaded, and it receives no property. | To indicate the set of properties that must be passed as a parameter to render() . | The Button brick. |
Behavior of setupExecution()
The setupExecution()
method returns a RxJS Observable, to which the brick subscribes. Everytime the observable produces a value, the brick calls update()
.
Example 1: an observable that merges two inputs
Let's take a look at the Control Flow Multiplexer
action. This action takes two control flows as inputs and waits for either one of them to be triggered before triggering its own output control flow. This is not possible with the default implementation of ActionBrick
, thus we need to override its behavior.
export default class ControlFlowMultiplexer extends ActionBrick {
setupExecution($) {
// We observe each input control flow and use the RxJS merge operator to trigger
// update() any one of them has been set
return rxjs.merge(...this.getInputs().map(input => $.observe(input)));
}
update($, inputs, [forwardEvent]) {
forwardEvent();
}
}
Example 2: an observable that completes directly
setupExecution($) {
return rxjs.of([]);
}
update($, inputs) {
// inputs here is an empty array
// update() is called only once
}
Example 3: an observable with a single value
setupExecution($) {
return $.observe('My Input');
}
update($, inputs) {
// inputs here is an array of one element, which can be destructured
const [myInput] = inputs;
// update() is called each time 'My Input' has a new value
}
Example 4: an observable which returns an array of values
setupExecution($) {
return rxjs.combineLatest([
$.observe('My Input 1'),
$.observe('My Input 2'),
$.observe('My Input 3')
]);
}
update($, inputs) {
// inputs here is an array of 3 elements, which can be destructured
const [myInput1, myInput2, myInput3] = inputs;
// update() is called each time the "combineLatest" observable has a new array of values
}
Example 5: an observable that returns null
setupExecution($) {
return $.observe('My Input').pipe(rxjs.map(myInput => {
return myInput > 0 ? myInput : null;
}));
}
update($, inputs) {
// inputs here is an array of one element, which can be destructured
const [myInput] = inputs;
// update() is called each time 'My Input' has a new value bigger than 0
}