signalizejs/signal
Reactive primitive that can be watched, used to create stores, or bound to element properties and attributes.
Installation
const {
signal,
Signal
} = await signalize.resolve('signal');
API
signal
Signals in a nutshell:
- A
signal
in Signalize is basically a “variable” that you can watch for changes or when its value is accessed. - Every signal you create while using Signalize is an instance of the
Signal
class. - The method
signal
creates a new instance of theSignal
class with the value you pass in during initialization.
Let’s start with how a signal can be used:
// 1. Creating a signal
const number = signal(0);
// 2. Setting a new value: from 0 => 1;
// You need to pass a value
number(1)
// 3. Getting signal value
// You just call the method
const actualNumber = number(); // => 1
// 4. We may want to watch the signal
// See docs below for more info
// 4.1 Triggered after every set
const unwatch = number.watch(({ newValue, oldValue }) => {});
// 4.2 Triggered immediately
number.watch(({ newValue, oldValue }) => {}, { immediate: true });
// 4.3 Triggered before the value is set
number.watch(({ newValue, oldValue }) => {
return {
// If false, the new value will not be set
settable: true,
// We can also modifie the value within the watcher
value: newValue
}
}, { execution: 'beforeSet'});
// 4.4 - And if we want to track the signal value usage
// we can watch it on every get call
number.watch(({ newValue, oldValue }) => {}, { execution: 'onGet' });
Signals can be watched for the following events. See the example below:
- on every get - To track places where the signal is used.
- before it is set -Useful to check the new value and possibly modify the value or block the setter.
- after it is set - Trigger some callback like recalculating variables that depend on the signal.
Signals are often used with the bind method.
Below is an example with two number inputs:
- Signals are connected to elements using the bind method.
- Signals are watched using
.watch()
method. - When any signal changes, it updates the output under the input elements.
numberB
cannot be lower thannumberA
. It’s always +1 higher thannumberA
.
A: <input id="numberA" type="number"><br>
B: <input id="numberB" type="number"><br>
<span id="output"></span>
<script type="importmap">{
"imports": {
"signalizejs": "https://cdn.jsdelivr.net/npm/signalizejs/+esm",
"signalizejs/event": "https://cdn.jsdelivr.net/npm/signalizejs/event/+esm",
"signalizejs/mutation-observer": "https://cdn.jsdelivr.net/npm/signalizejs/mutation-observer/+esm",
"signalizejs/scope": "https://cdn.jsdelivr.net/npm/signalizejs/scope/+esm",
"signalizejs/signal": "https://cdn.jsdelivr.net/npm/signalizejs/signal/+esm",
"signalizejs/bind": "https://cdn.jsdelivr.net/npm/signalizejs/bind/+esm"
}
}</script>
<script type="module">
import Signalize from 'signalizejs';
const { resolve } = new Signalize();
const { signal, bind } = await resolve('signal', 'bind');
// 1. Init Signals
const numberA = signal(1);
const numberB = signal(2);
// 2. Bind signals to inputs
// bind(element, attributes)
bind(document.querySelector('#numberA'), { value: numberA });
bind(document.querySelector('#numberB'), { value: numberB });
// 3. Bind signal to output.
bind(document.querySelector('#output'), {
// 4. In case we need to pass more than just a Signal
// into the bind function, we need to tell the function
// which signals to watch. The array contains signals
// to watch and the listener goes last [...signals, listener]
html: [numberA, numberB, () => `Outpout is: ${numberA + numberB}`]
})
// 5. Watch numberA,
// Execute watcher immediatelly {immediate: true }
numberA.watch(({ newValue }) => {
// 6. When number A is set, automatically increase
// numberB if it is smaller than A
if (newValue > numberB()) {
numberB(newValue + 1);
}
}, { immediate: true });
// 7. Watch number B, execute it before it is set
numberB.watch(({ newValue, oldValue }) => {
// 8. When number B is set, but is smaller than number A,
// return the old value and block setting the value
if (newValue < numberA()) {
return {
value: oldValue,
settable: false
}
}
}, { execution: 'beforeSet' });
</script>
Signal
Signal is a class that is used when creating a new signal with the signal
method.
Because Signal is a class, it can be easily extended for additional functionality. This way, we can make a specific Signal that can be reused within the application.
Let’s make a signal that will contain increment
method.
const { Signal } = await signalize.resolve('signal');
class Number extends Signal {
increment() {
this.set(this.get() + 1);
}
}
const number = new Number(0);
number.increment();
console.log(number()); // => 1