Although little time has passed since the release of the full version of Angular 19.0, we can already enjoy a new dose of improvements and features in version 19.1. What have the creators offered us this time? Let’s take a look at some of the new additions together.
Support for TypeScript 5.7
Angular 19.1 is fully compatible with the latest version of TypeScript 5.7.3, released just a few days earlier. This means we have access to the entire suite of up-to-date features.
Key updates in TypeScript 5.7:
- Improved Error Reporting: TypeScript 5.7 introduced enhanced error reporting mechanisms, enabling the detection of uninitialized variables.
- Support for ES2024: Added support for new methods such as Object.groupBy, allowing for more concise and readable operations on objects.
- Compiler Optimizations: Various improvements to the compiler have been implemented, speeding up the compilation process and enhancing overall performance.
You can check the full list of changes here: https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/
Visual Router Representation in DevTools
Angular DevTools is now enriched with a graphical representation of the application’s routing. This allows us to see individual paths that have already been loaded as a graph.
Additionally, signal visualization is now possible. However, at this stage, tracking signals in this manner is only possible through the private function ɵgetSignalGraph(). In the future, it is expected to be exposed in DevTools as an interactive graph showing signals and their dependencies.
To open the routing graph, open Angular DevTools, go to the settings, and then select the option „Enable Router Graph.”
On the right side, a new tab called „Router Tree” will appear.
Automatic Removal of Unused Standalone Imports
Until now, we have received warnings about unused standalone component and directive imports. Starting from Angular 19.1, they will be automatically removed using the following command:
ng generate @angular/core:cleanup-unused-imports.
New Features of NgComponentOutlet
NgComponentOutlet is a directive in Angular that allows the dynamic loading of components at a specified location within an application. In previous versions, its usage was limited to the .ts file. That was the case until Angular 19.1.
Before this update, to dynamically load a component:
- We had to use Angular’s API in the TypeScript file, such as ComponentFactoryResolver, to create component instances.
- This was more complex as it required TypeScript code to manage the creation and injection of components.
Example of the previous approach:
import { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';
@Component({
selector: 'app-root',
template: '<ng-container #dynamicContainer></ng-container>',
})
export class AppComponent {
@ViewChild('dynamicContainer', { read: ViewContainerRef }) container!: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) {}
loadComponent(component: any) {
const factory = this.resolver.resolveComponentFactory(component);
this.container.clear();
this.container.createComponent(factory);
}
}
In the latest version of Angular, we can dynamically load components directly in the HTML file using NgComponentOutlet. We no longer need to create component instances in the TypeScript code. Here’s an example:
<ng-container
*ngComponentOutlet="dynamicComponent"
#outlet="ngComponentOutlet">
</ng-container>
- *ngComponentOutlet=”dynamicComponent”:
Angular loads the component specified by the dynamicComponent variable. This variable can be a component class passed from the TypeScript file. - #outlet=”ngComponentOutlet”:
A local context (#outlet) is created, allowing interaction with the loaded component (e.g., access to the component’s instance and its API).
In the .ts file, we have the following code:
import { Component } from '@angular/core';
import { MyDynamicComponent } from './my-dynamic.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
dynamicComponent = MyDynamicComponent; // Przypisanie klasy komponentu
}
This has significantly simplified the process of dynamically loading components, eliminating the need to create component instances in the TypeScript code and providing greater flexibility in creating dynamic components.
This directive has also gained a new property—componentInstance. With it, we now have access to the instance of the component created by the directive.
With componentInstance, you can:
- Access the methods and properties of the component.
- Update data or pass new values to the component after it has been loaded.
- Perform operations on the loaded component, which was more difficult before because NgComponentOutlet did not provide direct access to the instance.
subPath in Multilingual Applications
In the context of multilingual applications, Angular 19.1 introduces an interesting subPath option, which is an extension of the baseHref feature. subPath automatically defines URL segments for different languages (e.g., /pl, /en) and organizes the generated files supporting a specific language into folder structures.
For greater context, let’s compare both solutions.
baseHref | subPath |
We need to build the application separately for each language, for example:
Result: Separate sets of files for each language. If you have more languages, the number of builds increases proportionally. |
The application is built only once with a single baseHref setting (e.g., /). Multilingual support is handled by Angular’s router, which parses URL subpaths (e.g., /pl, /en) and loads the appropriate resources.
Result: The build process is faster and more efficient because we generate only one version of the application. |
For each language, we need to place separate files on the server in the appropriate directories:
Result: This requires additional server configuration and more storage space since files are duplicated. |
All application files are shared and located in a single directory. The server handles different languages by analyzing the URL (e.g., /pl, /en) and redirecting to a single index.html.
Result: This is simpler to configure and takes up less space on the server. |
The URL is more static, for example:
If no additional mechanisms are applied, the application may not always reflect the language in the URL, which can hinder SEO. Result: We can achieve /pl/ or /en/, but only by building separate versions of the application for each language. |
Each language is clearly visible in the URL, for example:
Result: This is beneficial for SEO, as search engines can recognize separate pages for each language. |
We may require additional logic during the build process, such as loading translations for a specific language depending on the configuration.
Result: Changing the language in a running application may require a page reload, as baseHref alters the entire base path of the application. |
Angular Router enables dynamic language handling. Translations are loaded based on the URL subpath, which simplifies the code.
Result: Changing the language in the application (e.g., from /pl to /en) does not require a page reload. |
In short, when we use subPath, Angular automatically generates subdirectories and sets the baseHref for each language, which positively impacts the application’s performance and the developer’s workflow.
Below, we can see the file and folder structure as well as a snippet of code in the angular.json file using subPath.
/dist/
my-app/
pl/ (<base href="/my-app/pl/">)
index.html
main.js
styles.css
en/ (<base href="/my-app/en/">)
index.html
main.js
styles.css
"my-app": {
"i18n": {
"locales": {
"pl": {
"translation": "src/locale/file.pl.json",
"subPath": "pl"
},
"en": {
"translation": "src/locale/file.en.json",
"subPath": "en"
}
}
SSR: Redirecting to the preferred language
The server now redirects users to their preferred languages based on browser settings using the Accept-Language header. This feature works automatically without additional configuration.
HMR for templates
In Angular 19.0, HMR (Hot Module Replacement) was enabled by default for CSS files, and in version 19.1, it was extended to HTML files as well. This means that modifying code in a file will refresh only the specific template, not the entire application. As a result, we won’t lose the application’s state due to a refresh, and we’ll save time by avoiding a full-page rebuild.
You can see how this works in practice on the official Angular channel on YouTube: https://youtube.com/shorts/1h0ViHgAOGY?si=W_evMrztW0x6oZBX
Simplified Library Generation
Since ng-packagr has been integrated as a builder for the CLI (@angular/build:ng-packagr), to run the ng generate library command to create a library, we no longer need to have the @angular-devkit/build-angular package installed.
Summary
Angular 19.1 introduces a range of improvements that enhance the developer experience with the framework. New features include better support for TypeScript 5.7, improvements in DevTools, automatic removal of unused imports, and new functionalities for multilingual applications. Additionally, the application and library build process has been optimized with features like HMR for templates and automatic redirection to the preferred language.