Signals in Angular components
Signal API being now stable and out of developer preview, I tend to use it as much as possible when defining my component input
's and output
's (along with viewChild
, viewChildren
, contentChild
and contentChildren
).
import { Component, input, output } from '@angular/core';
@Component({
selector: 'app-button',
template: `
<button (click)="onClick()">
{{ label() }}
</button>
`,
})
export class ButtonComponent {
label = input.required<string>();
tooltipConfig = input.required<{ isConfirmable: boolean; /* other properties to style the tooltip */ }>();
clicked = output<void>();
onClick() {
this.clicked.emit(); // Signal outputs keep the same API than @Output ones.
}
}
Now, let's say we want to create a tooltip
variable that will contain the title
to display whether the button is confirmable or not (in tooltipConfig
input).
Before signals, we would have implemented the OnChanges
lifecycle hook and used the ngOnChanges
method to detect when one or both of the component inputs had changed, like:
ngOnChanges(changes: SimpleChanges) {
if (!changes.tooltipConfig) {
return;
}
const { previousValue, currentValue } = changes.tooltipConfig;
// Compare previousValue and currentValue to check if the value of tooltipConfig changed
}
Now, we can create a computed
signal from the input
signal:
tooltip = computed(() => {
const label = this.label(); // Will be triggered every time label changes.
const isConfirmable = this.tooltipConfig().isConfirmable; // Will be triggered every time tooltipConfig changes.
return isConfirmable ? `${label} - You will need to confirm first` : label;
})
The tooltip
computed signal will be re-computed each time one of the input changes (as in the ngOnChanges
method).