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 defer blocks have reached a stable state.
  • Angular Material 3 is now considered stable, with material.angular.io reflecting the new themes and documentation.
  • The experimental provideZonelessChangeDetection feature 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-content slots.
  • Route definitions can use functions for their redirectTo logic.
  • Event coalescing is now the default setting.
  • The HttpClientModule is 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(),
   ]
 });
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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 {}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 `/`;
      }
    }
  },
  // ...,
];
Enter fullscreen mode Exit fullscreen mode

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 NoInfer Utility Type
  • Object.groupBy and Map.groupBy
  • Support for require() calls in --moduleResolution bundler and --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.