Key Updates and New Capabilities
Since publishing my previous Angular guides, a major version has arrived. Here is a rundown of the notable modifications and additions, along with resources for learning more about each one:
- The control flow syntax and
deferblocks have reached a stable state. - Angular Material 3 is now considered stable, with material.angular.io reflecting the new themes and documentation.
- The experimental
provideZonelessChangeDetectionfeature offers a way to run change detection without ZoneJS. - Control state changes are now consolidated into a single event stream.
- Components can now define fallback content for their
ng-contentslots. - Route definitions can use functions for their
redirectTologic. - Event coalescing is now the default setting.
- The
HttpClientModuleis officially deprecated. - Support for TypeScript 5.4 has been added.
Additionally, angular.dev has become the official home for Angular documentation.
Zoneless Change Detection (Experimental)
Official docs: Angular without ZoneJS (Zoneless)
Merge request: feat(core): Add zoneless change detection provider as experimental
This release introduces a new experiment for triggering change detection without relying on ZoneJS. When enabled via provideExperimentalZonelessChangeDetection, Angular schedules change detection using its own APIs. This includes scenarios such as:
- Invoking
ChangeDetectorRef.markForCheck. - Calling
ComponentRef.setInput. - Modifying a signal that is being read in a component's template.
- Triggering bound host or template event listeners.
- Attaching a view that has been flagged as dirty by one of the previously mentioned actions.
- Removing a view.
- Registering a render hook, although templates are only refreshed if those hooks perform one of the actions listed above.
This new provider can be tested with components that use the OnPush change detection strategy:
bootstrapApplication(App, {
providers: [
provideExperimentalZonelessChangeDetection(),
]
});
Support for this zoneless mode has also been integrated into Angular CDK and Angular Material.
Consolidated Control State Events
Official docs: AbstractControl.events
Merge request: feat(forms): Unified Control State Change Events
The AbstractControl class, which serves as the foundation for FormControl, FormGroup, and FormArray, now includes a new events: Observable<ControlEvent<TValue>> property. This observable emits events whenever the control's value, status, pristine state, or touched state changes.
@Component({
selector: 'app-abstract-control-events',
standalone: true,
imports: [ReactiveFormsModule],
template: ` <input [formControl]="titleInputControl" /> `,
})
export class AbstractControlEventsComponent {
titleInputControl = new FormControl<string | null>('', Validators.required);
constructor() {
this.titleInputControl.events.pipe(takeUntilDestroyed()).subscribe(console.log);
}
}
For instance, interacting with the input in the example—clicking in, typing a character, and clicking out—will log the following sequence of events to the browser's console:
PristineChangeEvent {pristine: false, source: FormControl2}
ValueChangeEvent {value: 'a', source: FormControl2}
StatusChangeEvent {status: 'VALID', source: FormControl2}
TouchedChangeEvent {touched: true, source: FormControl2}
Fallback Content for ng-content
Official docs: Content projection with ng-content
Merge request: feat(core): add support for fallback content in ng-content
It is now possible to define default content for an <ng-content> element. This fallback will only be displayed when the parent component does not supply any content for that projection slot:
@Component({
selector: 'app-header',
template: `
<ng-content select=".title">Default tilte</ng-content>
<ng-content select=".explanation">There is no explanation for this title</ng-content>
`,
})
export class HeaderComponent {}
@Component({
selector: 'app-wrapper',
template: `
<app-header>
<span class="title">First chapter</span>
</app-header>
`,
})
export class WrapperComponent {}
The output of these examples is rendered as follows:
<app-wrapper>
<app-header>
<span class="title">First chapter</span>
There is no explanation for this title
</app-header>
</app-wrapper>
Dynamic Route Redirect Functions
Official docs: Common router tasks: Setting up redirects
Merge request: feat(router): Allow Route.redirectTo to be a function which returns a string or UrlTree
The redirectTo property of a route can now be defined as a function that returns either a string or a UrlTree. This change allows for redirect logic that can adapt based on the app's current state:
export const routes: Routes = [
// ...,
{
path: "prods", //legacy path
redirectTo: ({ queryParams }) => {
const productId = queryParams['id'];
if (productId) {
return `/products/${productId}`;
} else {
return `/`;
}
}
},
// ...,
];
Default Event Coalescing
Official docs: NgZoneOptions
For all new applications, event coalescing is now activated by default (eventCoalescing: true). This setting helps to minimize the number of change detection cycles, potentially enhancing the overall performance of an application.
HttpClientModule Deprecation
Merge request: refactor(http): Deprecate HttpClientModule & related modules,Migration schematics for HttpClientModule
Starting with version 18, the recommended approach for configuring the HTTP client is through the provideHttpClient() and provideHttpClientTesting() functions. Consequently, the HttpClientModule and HttpClientTestingModule are now marked as deprecated.
Running ng update @angular/core will automatically migrate your codebase to use the new functional providers, moving away from the deprecated modules.
TypeScript 5.4 Support
Merge request: feat(compiler-cli): drop support for TypeScript older than 5.4
Several notable features from TypeScript 5.4, as outlined by Daniel Rosenwasser, include:
- Preserved Narrowing in Closures Following Last Assignments
- The
NoInferUtility Type Object.groupByandMap.groupBy- Support for
require()calls in--moduleResolution bundlerand--module preserve - Checked Import Attributes and Assertions
- Quick Fix for Adding Missing Parameters
- Auto-Import Support for Subpath Imports
Meet the author
I'm Gergely Szerovay. My background spans data science and full-stack development, and I've spent the last several years as a frontend tech lead with a focus on Angular. In that capacity, I keep a close eye on how Angular and the broader frontend landscape are changing.
Angular has progressed swiftly in recent years, and with the surge of generative AI, our development practices have shifted just as quickly. To track the changing nature of AI-assisted engineering, I've started building AI tools openly, sharing the journey on AIBoosted.dev — you can subscribe over there 🚀
You can connect with me on Substack (Angular Addicts), Substack (AIBoosted.dev), Medium, Dev.to, X, or LinkedIn for more on Angular and on building AI-driven apps with AI, TypeScript, React, and Angular.
