In May 2024, the Angular Version 18 was released. Manfred discussed the new features in a detailed post.
In this post, we want to present the additional features of the minor release 18.2 (including release 18.1).
@let it begin
While some highly motivated Angular bloggers introduced the @let feature already back in May, it was yet released with Angular 18.1 on July 10th, 2024. It enables developers to define a reusable variable in the component's HTML template (sometimes referred to as the HTML-file) and is part of Angular's new template syntax – all the pretty things starting with "@".
Let’s check out its syntax:
@let maxLength = 42; // a valid expression (like number | 'string' | JavaScript expression)
Now we can use the @let-variable:
<input name="from" [(ngModel)]="from" [maxlength]="maxLength" />
Dynamic @let
You can also use the value of a template reference variable (or, as we sometimes call it a template handle, which makes total sense to Austrians since we also call chickens "Hendl" 🐔):
<input #from name="from" [maxlength]="maxLength" />
@let fromValue = from.value;
So it seems like now we have to distinguish between:
- Local template variables with @let (see Angular docs) and
- Template reference variable with #handle (see Angular docs)
Okay, that will be interesting to explain in the next Essential Workshop. @let's see.
Async @let
Now we finally come to the interesting and useful part. If we needed the latest value of an observable (or a subject likewise), we needed to apply the so-called ngIf hack until now. While users of the *ngrxLet directive have used something similar for years and users of the even better (performance-wise) rxLet even for decades (okay, I might exaggerate a bit here), we – the true Angular believers – had to use ugly ngIf or – with the new template syntax – the still ugly @if constructs like this:
@if (flights$ | async; as flights) {
// basic @if hack
@for (flight of flights; track flight.id) {
[...]
}
}
Or, even more complicated, like that:
@if ({ flights: flights$ | async }; as data) {
// advanced @if hack, will also show the @if block before the 1st flights$ emit
@for (flight of data.flights; track flight.id) {
[...]
} @empty {
No flights.
}
}
Now this becomes:
@let flights = flights$ | async;
@for (flight of flights; track flight.id) {
[...]
} @empty {
No flights.
}
@let's go! That looks much better! And it also closes one of the most upvoted Angular GitHub issues from March 2017.
@let-variables are read-only and cannot be reassigned. However, their value will be recomputed on each change detection.
Please note, that you can also override existing symbol names (like component class members). Not sure though, if that's a good idea. You won't get a compiler error/warning unless you want to use the component class member before defining the @let-variable with the same symbol name. Only in that case will the compiler complain that you use something that has not been defined yet (NG8016: Cannot read @let declaration 'flights' before it has been defined.). So, we can conclude that using a @let-variable hides the component class member with the same name from the component's HTML template.
You probably skipped this section, because you've stopped using RxJS since basic Signals are out of Developer Preview already. Yeah, maybe one day you'll return to RxJS, because it's still the more powerful option 😎
In any case, we have something more to cover here.
Two new migration schematics
Now to a (or two) completely different topic.
Are you already using the fabulous migration schematics we've discussed recently?
Existing schematics
For the new template syntax control flow, more details in this post.
ng g @angular/core:control-flow
For the new app builder, more details also in this post.
ng update @angular/cli --name use-application-builder
For standalone components, more details in this post.
ng g @angular/core:standalone
New schematic to convert standalone component routes to be lazy loaded
For all standalone components used in the router, please lazy load 'em:
ng g @angular/core:route-lazy-loading
I've just tested this migration on some of my projects, and it really pushed my lazy loading a bit further.
The script even tells you when you need to migrate components of your NgModules to standalone to be able to lazy load them as well (using the previous migration).
New schematic to convert constructor-based DI to the new functional inject()
The Angular team recently stated that both variants will continue being supported in the foreseeable future (thanks to Rainer for bringing up this question in the PR). Nevertheless, I've been advocating the new incject
for quite some time. Until I've read this thread on Angular GitHub. After reading that discussion, I was definitely a chunk wiser, and thus now I'm kind of in a neutral stance on which is the better choice – preferably a consistent one in a codebase. There are good arguments for both. Nevertheless, if you want to use the new functional approach, you can now use the official migration schematic:
ng g @angular/core:inject-migration
Pro-tip: After running the migration you need to run Prettier to get rid of the created empty lines. In some future post I'm going to share my best practices on setting up Prettier for Angular projects.
That's all folks
Yes, there are plenty of other improvements and fixes, but I don't think they will have a huge impact on our lives. After the big changes from 15 to 17, maybe it's time to chill a bit. Still waiting for Signal inputs, model and queries to become production-ready, but I think don't think we'll get that in 18.3 in six weeks. The next major release 19 is planned for November 2024.
In the meantime, I want to recommend:
- this post by Loraine Lawson on Minko Gechev's view on frontend frameworks and the convergence of Angular and Wiz
- this video feat. Emma Twersky about the future roadmap of Angular at the Angular Meetup Graz on June 24th, 2024
- or for something completely different, check out the Pixel 9 Pro – I just ordered the best option for iOS refusers 😏
Workshops
If you want to deep dive into Angular, we offer a variety of workshops - both in English and German.
- Accessibility Workshop, next on Sep. 6th ♿
- Performance Workshop, Sep. 2nd to 4th 🚀
- NG Styling Workshop 🎨
This blog post was written by Alexander Thalhammer. Follow me on GitHub, X or LinkedIn.