Skip to main content
Version: 2.4

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.

tip

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:

DRAWBase class in CODEDefault behaviorSome reasons to override setupExecution()Examples 
FunctionsBrickBy 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.
ActionsActionBrickBy default, update() is called when the control flow is triggered.When there is more than one control flow.The Control Flow Multiplexer brick.
Visual componentsVisualBrick or ReactBrickBy 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
}