Update 2023–10–07: I have updated this to the final syntax form with @
New Template Syntax, Built-In Control Flow, a farewell to structural directives? Not a lot has been changing in recent years. Angular has been stable for some devs and stagnant for others. Now it’s moving forward at light speed. But where exactly is it headed?
Angular proposes a transition from the current structural directives (NgIf, NgForOf, NgSwitch) to a new built-in syntax. If you’re not already following the RFCs (Request for Comments), please do. In meantime I am going to help you understand what’s coming.
Revamping Control Flow
Angular team aims to replace the existing structural directives (NgIf, NgForOf, and NgSwitch) with a more modern, macro-like syntax. While the structural directives are not going away completely, because the concept is going to stay — this new way of writing your template is going to be the preferred one. It’s backwards compatible and for some time you are going to be able to use both old template style and new one in different files.
Change aims to cover better readability and provide smother way to adapt for wider audience in Frontend world.
Before
The trackByFunction in Angular is a custom function used for optimizing performance when iterating over large collections using *ngFor
. In current syntax it takes only a function, in new way it’s going to work just with properties.
Angular will track changes in the collection based on each item’s id, instead of its identity. This is useful when items in the collection have unique ids, improving efficiency when the collection is updated.
trackByFunction(index, item) {
return item.id;
}
<div *ngFor="let item of items; index as idx; trackBy: trackByFunction">
Item #{{ idx }}: {{ item.name }}
</div>
After
@for (item of items; track item.id; let idx = $index, let e = $even)
{
Item #{{ idx }}: {{ item.name }}
}
This new syntax is keeping several implicit variables like $index, $first, $last, $even, and $odd within for row views. These are available for use directly, but can also be aliased using the ‘let’ segment. The new syntax also emphasizes using ‘track’ for loops to improve performance and optimizes list diffing by enforcing tracking.
@for (item of items; track item.id)
{
{{ item }}
}
@empty
{
There were no items in the list.
}
One crucial feature introduced is the ‘empty’ block which allows developers to display a template when there are no items in the list. Also, Angular is changing how it handles list diffing. Rather than using the customizable IterableDiffers, Angular will provide a new optimized algorithm for better performance.
If-Else Blocks
If you found the original way of working with ng-container & ng-template alongside *ngIf
structural directive not intuitive enough — New Control Flow might have an answer for your troubles.
Before (in theory)
<ng-container *ngIf="cond.expr; else elseBlock">
Main case was true!
</ng-container>
<ng-template #elseBlock>
<ng-container *ngIf="other.expr; else finalElseBlock">
Extra case was true!
</ng-container>
</ng-template>
<ng-template #finalElseBlock>
False case!
</ng-template>
After
@if (cond.expr)
{
Main case was true!
}
@else if (other.expr)
{
Extra case was true!
}
@else
{
False case!
}
Switch Block
The ‘switch’ block takes place of *ngSwitch
which. New way of writing is said to bring in substantial benefits like enhanced template type-checking and no need for container elements to hold condition expressions. Here’s a quick peek at how it would look:
@switch (condition)
{
@case (caseA)
{
Case A.
}
@case (caseB)
{
Case B.
}
@default
{
Default case.
}
}
What About Migration?
Migration to the new syntax is promised be relatively smooth. Angular team is working on an automated migration schematic to convert from the old to the new syntax. However, developers might need to be cautious about any custom diffing algorithm used in their applications as it could affect the new ‘for’ directive’s behavior.
Future Opportunities
The Angular team envisions extending this new syntax to accommodate more JS loop flavors, including async iteration, and for-in loops. Potential future improvements also include virtual scrolling and destructuring support.
There is also another RFC showing new feature in action — this feature is based new Built-In Control Flow. Checkout RFC for Deferred Loading
FAQ Recap
Let’s quickly address some common concerns developers might have about this new control flow syntax:
Existing structural directives: The current structural directives (NgIf, etc) will continue to work. However, Angular will strongly encourage developers to switch to the new syntax.
Structural directive concept: It will not be removed and remains an essential feature in Angular.
Syntax highlighting: Yes, the Angular Language Service will highlight keywords and expressions within the new control flow blocks.
Effect on query results: The new control flow will not affect query results.
Need to import new control flow: No, it will be built into the template language and automatically available to all components.
Performance: The new control flow might offer marginal improvements, particularly for ‘for’ and diffing.
Custom block groups and directives: At present, the new syntax doesn’t support libraries to define custom block groups, and you can’t add directives to the new control flow blocks.
What do you think?
This proposed syntax change is going to affect the way you write your templates. Do you think it’s needed? Is this change going to improve your DX and bring new devs aboard that prevously preferred to use different frameworks?
My main concerns lie within the transition period. We have a significant change in reactive primitive with Signals and now new Template Syntax is being introduced. It’s definitely coming together to paint a bigger picture that hasn’t been unveiled to us yet. For some time Angular devs are going to get many options to handle reactivity: RxJS, Signals, Promises, Change Detection (zone.js) + 2 ways of writing templates.
It will definitely take a long time to fully transition to the new vision and it’s not like you can speed this process up. Now the question would be, is the cost of these advancements worth what we are getting in the end?
Make sure to let me know and have a discussion!
I hope you liked my article!
If you did you might also like what I am doing on Twitter. I am hosting live Twitter Spaces about Angular with GDEs & industry experts! You can participate live, ask your questions or watch replays in a form of short clips :)
If you are interested drop me a follow on Twitter @DanielGlejzner — would mean a lot :). Thank You!
Oh no! My Coffee cup is empty :( …
… if you want to refill go ahead :) https://ko-fi.com/danielglejzner
Top comments (44)
Am I the only one that is disgusted by this change? I liked Angular because you write html. It's easy to learn and is visually appealing. This is an ugly mess.
I'm sick of the Angular team trying to reinvent the entire framework every two years. It makes maintenance incredibly difficult and pushes people towards lighter and more stable frameworks. If people like this syntax then let them switch to a tool that uses it.
I don't mean to sound like the grumpy old guy, but the rapid changes in frontend tools makes my just want to use underscore and plain JS/TS.
You really should try it. Every web developer should, I'm not joking. After that, you will understand much better how frameworks work and what value they bring.
I started doing frontend work before Angular was even a thing, you don't gotta tell me that. But modern frameworks have gone off the deep end and frequently end up being more of a burden than a help: Constant breaking changes and changes in convention, bloated dependencies, neglect for debugability, etc. At my last company every time we upgraded Angular it was a full month endeavor to coordinate updates across 5+ teams, and for what? Slightly smaller builds and some features we didn't use? I deal with React currently, which has its own issues.
I'm not saying don't use them, I just want a bit more stability in the framework space. I'd love to get to pick the framework and choose one that promises to stay out of the way. The big names have so many engineers who want to make things "better" and end up causing more problems.
Try Lit - as far as I know, it's the most stable web framework.
The change, discussed in this article, is not breaking, though.
Yeah, its more of the style change that bugs me. I like the style of html tags and templates, it looks cleaner imo because it fits the style of the rest of the template. This brings back mustache style brackets where Angular helped us reduce, its ugly imo.
This proposal would be a great optional plugin, it doesn't need to be the default. It seems like leadership changed and so did the vision.
I'll look at Lit though.
Talking about stability:
Syntax is a moving target on the frontend and interestingly there is a destination (which I talked about in my article), and until we get there, syntax can't be stable!
You'd realise how much we can skip if we could just use plain JS for rendering logic instead of re-inventing a new language (every new turn) that maps to the same JS constructs! (See also Eckehard's comment.)
You can do this - stop using Angular and start using vanilla JS.
I haven't read the full story, but this doesn't seem like it's going to force you use the new syntax, the old syntax is still just directives, so unless they're removing directives completely then you should have backwards compatibility.
I read the post and its not entirely clear. In the title its called an alternative syntax, but in the body they describe building migration tooling. That implies they wouldn't support both in perpetuity.
Both are going to be supported for a period of time :)
This is unfortunately not correct. The original syntax also does not parse as HTML (well anything parses as HTML, however, it will not come out as you've entered).
I also was under the wrong assumption that angular calling the template files .html and essentially using attributes is for that reason - but the parser and it's logic is still custom (and needs to be).
I love these changes.
I just did a new standalone app, using only Signals. That, and the new inject() functional stuff is so so so awesome to work with.
I cannot wait to be able to ditch ZoneJS.
This new syntax is basically a copy of the Svelte-syntax, which makes it easier for some new developers to onboard, I guess.
Back again - now we're running everything zoneless and it's a bliss. so nice
there is "Alternatives Considered". please check source link. i would like to see this syntax instead
Yeah, I read over the entire post. That syntax looks fine imo. I don't mind things taking a few more lines if it is consistent and easy to read. This is **much **easier to read than than trying to parse over Mustache style syntax they are trying to push. We moved away from that for a good reason, this is regression imo.
Svelte uses it and it rocks
I'm not repulsed by it, but I'm not particularly fond of it either. I'm just dreading the inevitable syntax migration when the current version becomes deprecated.
I love it, to be honest it's amazing with all the new changes. I didn't think much of them until I made a new app, standalone, only using signals, and inject() to make functional ngrx effects etc. Such an amazing experience that I cannot go back now.
That's fair enough - new projects are one thing, but having to maintain an existing project with 1,000s of files is another. I'm guessing it'll be easier than AngularJS -> Angular 2, but I suspect it won't be as simple as running a migration script either.
Thanks for sharing that the overall development experience is smoother.
Bro started doing frontend work before Angular was even a thing, we better shut up 🤣
I personally really like this. Anything to make code easier to read is always a win
As a Svelte dev, it is nice to see the influence here ☺️
The readability argument is a strong one, especially for those among us who are more senior who tend to read a lot of code.
Yep, love this
Feels like Svelte it's becoming influential. But that's a good thing right?
This seems much similar to templating using handlebars.js
It's great to see frameworks take over the good parts from each other. Ember.js has been using this type of control flow too for years and I personally much prefer it over inline attributes.
Its a nice start! But before moving back to Angular i want to see svelte like 3rd party js library level compatability
You really should check it out, Signals and inject() makes it sooooooo nice
Really cool post. Makes me want to check bleeding edge Angular.
It's awesome. Standalone-app with no modules, inject() function makes you able to easy inject Services into functions, etc etc. Wondeful
The angular plugin for VScode will need some additional schematics, such that when I start typing "if", it will generate the code block for me, nonetheless I like the new syntax. Seems like current FE starts to become more and more similar to each other.
This is interesting. I've been using Angular for a while now, and have become rather acquainted with how it currently works. With that said, I'm curious to see how these changes are adopted by the global Angular community.
Thanks for the summary!
Personally, I don't find the new syntax significantly easier to read, but maybe it's because I got used to the current syntax.
I wonder what's driving the change. Maybe it wants to be like other frameworks for more popularity; or maybe it's because Google just likes changing its tech often.