Angular Signals - an overview
- Published on
When data in an application changes, most of the time, the views have to change too. My usual approach for this kind of situation totally depends on the use case. There are cases wherein I would only need two-way binding - [(ngModel)]
if it involves inputs, event binding - (click)
which is usually used in buttons, ChangeDetectorRef
which you just trigger through detectChanges()
by calling it after performing some asynchronous operation, or lastly, which is my favorite, using Observables and RxJs!
Now, I'm going to talk about the last one which is using Observables. Observables are used for handling events and multiple values.
Let me give you an example:
app.service.ts
updateTime(): Observable<Date>{
return new Observable(
observer => {
setInterval(() =>
observer.next(new Date())
, 1000);
}
);
}
main.ts
@Component({
selector: 'app-root',
standalone: true,
template: `
<h2>{{ myTime }}</h2>
`,
})
export class App {
public myTime: Date;
constructor(private appService: AppService) {
this.myAppService.updateTime()
.subscribe(time => this.myTime = time );
}
}
What this does is that time is returned every 1 second. The view also updates due to the fact that the value returned by updateTime()
is passed to myTime
which is displayed on the HTML. Simple, right? And observables can do so much more especially when you use it with the right RxJs operators. But that's not the main agenda of this blog post.
In this blog post, I'm going to talk about Angular Signals. They were introduced in the developer preview of Angular 16 and are currently working in Angular 17. Angular Signals give developers a more powerful approach toward a more reactive style of developing in Angular. With the use of signals, Angular will be able to identify which values need to be changed and only update those.
Remember using zone.js
? Yeah, Angular Signals aim to get rid of that too. Not literally, remove it but through signals, we may not have to use zone.js
anymore.
Here's the good thing: We don't have to subscribe to observables too! With signals, gone are the days wherein you'd have to use .subscribe()
all the time!
Let's modify the code above to use Angular Signals:
app.service.ts
private _time = signal<Date>(new Date());
constructor() {
setInterval(() => this._time.set(new Date()), 1000);
}
get time() {
return this._time.asReadonly(); // Expose a read-only version of the signal
}
main.ts
@Component({
selector: 'app-root',
standalone: true,
template: `
<h2>{{ myTime }}</h2>
`,
})
export class App {
public myTime: string = '';
constructor(private appService: AppService) {
effect(() => {
this.myTime = this.appService.time().toString();
});
}
}
Now, you still get the same value as you did in the previous code but this time, you're using signals! No need to subscribe.
Angular Signals can either be Writable or read-only.
Instead of calling next()
when passing data from an observable, we simply set a new value to the signal _time
. set()
is one of the functions of a Writable signal. It changes the value of a Writable signal. There is also another function, update()
which updates the current value of a signal.
There are also signals called Computed Signals that are read-only. They derive their values from other signals. You cannot use the functions of Writable Signals to Computed Signals.
See this example below:
@Component({
selector: 'app-root',
standalone: true,
template: `
<h2>{{ tripleQuantity() }}</h2>
`,
})
public quantity = signal<number>(1);
public tripleQuantity = computed(() => quantity() * 3); // will work!
private testError() {
this.tripleQuantity().set(1); //error!
}
Also, when you display a signal on the HTML side, you have to write it like a function - with parentheses tripleQuantity()
.
Lastly, we also have effects! If you've tried coding in React, this works similarly as useEffect
. Signals help users by notifying them when their values change. However, there are time when we would need to be notified every time these values change. In the example above, I placed myTime
within the effect because I wanted its value to be updated whenever this.appService.time()
changed.
In conclusion, Angular signals make it easier to manage state changes without needing subscriptions. Using writable and computed signals, along with effects, allows for more responsive and easier-to-maintain applications. Embracing these features simplifies handling dynamic data and improves the development experience.
Working StackBlitz example of the code earlier can be found here: Angular Signals Example
Photo by Carlos Alberto Gómez Iñiguez on Unsplash