Back to the homepage
Angular

Angular 15 (14+) – what’s new?

After the very successful release of v14, Angular team doesn’t slow down and is also providing us with a lot of new and interesting features in Angular 15. In addition, also in minor, 14.X versions there were some noteworthy features introduced, which we have not yet described on our blog. So below you will find information about the most important of them.

Stable standalone APIs

Starting with version 15, the standalone APIs drop the developer preview label and become stable, so we get the green light to safely utilize them in our applications, including production use. Later in this article we will see that many of the recent changes are based on this very fact.

If you haven’t already done so, I also encourage you to read our article about the standalone components feature itself:
Angular Standalone API.

Router

Angular 14.1 brought us a new type of guard – canMatch. So what’s the difference between this new one, canLoad (this one tells us whether we can load a route that references a lazily loaded module) and canActivate/canActivateChild (they tell us, respectively, whether we can activate a child route/route)? CanMatch works, in a sense, at a different, “earlier” stage and decides whether the current url can be matched against a given route. Thus, it can play a similar role to both canLoad (which, by the way, it will eventually replace) and canActivate*, however when it returns false, subsequent routing configuration entries are processed.

This means we gain a new possibility – defining a route with the same path, but navigating to different places based on the logic implemented by the guard. This is useful, for example, when handling different user roles, or conditionally loading another version of the feature based on feature flags. Usage example:

We didn’t have to wait long for the router changes caused by the introduction of standalone components, because already in version 14.2 appeared APIs supporting the module-less approach.

In practice, this means that our application no longer needs to use RouterModule at all to implement routing. Instead, we get a whole set of alternative APIs (which, by the way, have the advantage of being easily treeshakeable):

A full list of functions and options we can use with provideRouter can be found in the documentation.

Another new feature introduced in the same version to this area is support for functional guards and resolvers. This means that it is possible to implement them in the form of plain functions, so we can say goodbye to the classes being so far the only option here. The introduction of this concept triggered many reactions among the community, both positive and negative. Some developers see this as a new direction of the framework. Personal preferences aside, one thing cannot be denied – it requires much less boilerplate. What is more, it is now very easy to create higher-order, parametrized functions returning a properly configured version of the guard based on that. The usage looks as follows (you can easily compare with the earlier example):

HttpClient

The HTTP client also received some changes in Angular 15.

The first is, same as for the router, the APIs for the module-less approach.

Again, the full list of functions and options we can use with provideHttpClient can be found in the documentation.

Another new feature, again similarly to the router, is the support for functional interceptors. Usage is as follows:

Directive Composition

One of the most wanted features in the framework was the ability to reuse directives and apply their behavior to other directives or components. Version 15 brings the implementation of this mechanism.

Until now, there have been few possibilities to (partially) achieve a similar result, such as the use of inheritance, where the main limitation is that only one base class can be used. Another idea, used, for example, by Angular Material, is the use of TypeScript mixins, but forces a specific approach to code shared in this way, heavily complicates implementation and doesn’t allow the use of Angular APIs in mixins.

The current implementation is very flexible and opens up a whole spectrum of new possibilities – we are mainly limited by our own creativity.

The only major restriction is that only standalone directives can be applied to our directives/components (these on the other hand don’t need to be standalone). An example of usage is as follows:

The above piece of code applies the NgClass and CdkDrag directives to our component. The first one doesn’t expose any inputs/outputs, so you won’t be able to use them in the template where our component is used. The second, on the other hand, exposes both input and output, with an alias defined for output. Therefore, the use of our component could look as follows:

So the NgClass directive only applies its default behavior to the component (which, in the case of NgClass, means no changes at all). So can we control its behavior in any way? This is possible using the inject function, which allows us to inject the instance of the directive into the component and manipulate its properties from within the component:

Below you will find a simple, interactive example of the implementation of the various elements described above. It is worth noting the behavior of input/output aliases when applying several directives.

As a bonus, some ideas for using directive composition:

https://twitter.com/_crisbeto/status/1582475442715385858
https://twitter.com/BartBurgov/status/1582692518986100736
https://twitter.com/NetanelBasal/status/1581614761212796935
https://twitter.com/i_beqiri21/status/1592434518291808261
https://twitter.com/ArmanOzak/status/1597279998716481536

Developer Experience Improvements

Stack traces & debugging

Improvements in this area are possible thanks to the cooperation of the Angular team and the Chrome team. The basis for this is the ability to mark scripts as “external” and thus exclude them in the functions of development tools (e.g. stack traces). Starting with Angular 14.1, the contents of the node_modules and webpack folders are marked in this way. It is worth mentioning that this mechanism is available to all developers, so for example authors of other frameworks can use it as well.

Returning to Angular, the result when displaying errors in the console is a stack trace that omits scripts that are probably not in the developer’s area of interest (such as zone.js). Also, when debugging and iterating over subsequent instructions in the code, those belonging to excluded scripts are skipped.

stack trace
(screenshot of the previous stack trace will not be posted, because as you can see from the last link above, it contains over 200 lines)

The second new feature worth mentioning is stack trace linking for asynchronous operations – the code executed following the completion of an asynchronous action can now be properly linked with the code initiating this action (e.g. a click and call to the server) – this is possible thanks to the introduction of the so-called Async Stack Tagging API mechanism in Chrome.

linked call stackvsunlinked call stack

Lazy loading

Version 15 also brings a minor change when it comes to the lazy loading syntax – from now on, the import of default exports from a given file can be slightly shorter (this applies to both loadChildren and loadComponent).

Language Service

Another DX-related improvement is the possibility to automatically import components whose selectors were used in another component’s template (applies to both standalone and module-based).

language service component imports Angular 15

Summary

This article shows that there have been many significant and interesting changes in Angular since the introduction of version 14.0. What’s more, this article describes only a subset of the most important ones, not mentioning, for example, the introduction of an alternative esbuild-based builder, the NgOptimizedImage directive, or a complete refactoring of Angular Material (these topics deserve separate articles).

What should we expect in the future? We can expect the release of Angular 15.1 very soon, where, among other things, there will be support for TypeScript 4.9, deprecation of canLoad guards and further improvements in the Language Service area.

When it comes to the long-term plans, it is worth taking a look at the roadmap, which was also updated at the beginning of November. It includes a number of quite “hot” topics such as – at long last – improvements for SSR, or support for the zone-less approach and local change detection (probably based on the concept of signals). We look forward to updating you on these news on our blog soon!

About the author

Krzysztof Skorupka

Angular Team Leader at House of Angular. Krzysztof guides team members and helps them develop a senior software engineer skill set, while developing Angular web apps by himself. He is interested in business analysis and architecture of web apps, adapted to client needs.

Don’t miss anything! Subscribe to our newsletter. Stay up-to-date with the latest trends, tips, meetups, courses and be a part of a thriving community. The job market appreciates community members.

Leave a Reply

Your email address will not be published. Required fields are marked *