Angular 17 New Features for Modern Web Development!

Trung NguyenTrung Nguyen
14 min read

In October 2023, Angular celebrated its 13th anniversary, and shortly after, in November, Angular made its grand entrance, bringing a wave of excitement and change. Not only did this release mark a milestone in Angular's journey, but it also introduced a brand new logo. This way Angular signals a new era for the framework. Angular, from its inception with AngularJS, one of the popular JavaScript frameworks following a complete rewrite at Angular 2 to the latest version 17, continues to shape the landscape of web development. Join us on the exploration of the revamped major release of Angular, and discover the innovative standards it sets for performance and user experience in the ever-evolving world of web development with new angular 17 features.

Summary of Angular 17 New Features

Angular 17 is a performance revolution! Unveiling deferrable views for a turbocharged experience, this release propels Angular to new speeds, boasting up to 90% faster run time, and it has just brought significant improvements to the loading time. Beyond the code, Angular 17 flaunts a sleek new look, an interactive learning journey, and a host of enhancements. It's not just an upgrade; it's lot more than that for the future of web applications and front-end development!

Major changes in Angular 17

  • Boosting performance: Speed up builds with up to 87% faster hybrid rendering and up to 67% improvement in client side rendering.

  • A sleek makeover, showcasing features in its fresh new look with all new interactive learning journey designed to make mastering Angular

  • Revamped hybrid rendering experience with @angular/ssr package

  • New lifecycle hooks: afterRender and afterNextRender

  • New application builder: Vite and esbuild the default for new projects

  • Dependency injection debugging capabilities in Angular DevTools

  • All the ng generate commands will now scaffold standalone components, directives, and pipes

  • Experimental view transitions support to enable transitions when changing DOM

  • Style and styleUrls as strings

Future-looking documentation

Angular has a brand-new documentation at angular.dev, coinciding with its updated brand. The revamped site boasts a user-friendly structure, many improvements to guides, and enriched content. Notably, it introduces an interactive learning journey, made possible by WebContainers. This feature empowers users to explore and learn Angular and the Angular CLI at their own pace, all within the convenience of a modern web browser. It's a simpler and more accessible way to master Angular's intricacies.

Built-in control flow

Angular has introduced a new block template syntax, offering this one of the powerful features through straightforward, declarative APIs. Behind the scenes, the Angular compiler transforms this control flow syntax into efficient JavaScript instructions capable of handling control flow, lazy loading, and more. With several challenges encountered by developers using ngIf, ngSwitch, and \ngFor*, the angular team has responded with a new, built-in control flow tailored to simplify angular development.

Let's dive into the key features that make this a significant advancement:

  • Ergonomic Syntax: More intuitive and developer-friendly syntax, closely aligned with JavaScript, reducing the need for frequent documentation lookups.

  • Better Type Checking: Improved type checking for more reliable and error-resistant code.

  • Build-time Concept: It minimises runtime footprint, potentially reducing bundle size and aligning with Core Web Vital metrics.

  • Automatic Integration: Seamless integration into your angular templates without additional imports, streamlining your development workflow.

  • Significant Performance Improvements: Significant improvements to the performance ensuring faster runtime and enhanced user experiences.

Conditional Statements

Let's dive deeper into the functionality of \ngIf*, specifically examining how conditional rendering is done with the new built-in control flow introduced in Angular 17.

<div *ngIf="paymentSuccessful; else errorMessage">
  Payment successful! Thank you for your purchase.
</div>

<ng-template #errorMessage>
  Oops! Payment failed. Please try again.
</ng-template>

With the built-in @if statement, the code looks like:

@if (paymentSuccessful) {
  Payment successful! Thank you for your purchase.
} @else {
  Oops! Payment failed. Please try again.
}

The ability to directly provide content for @else is a significant simplification compared to the legacy \ngIf alternative. The current control flow also makes it trivial to incorporate @else if*, a functionality that was historically impossible.

Looking at the \ngSwitch* code below will provide a clear understanding.

<div [ngSwitch]="paymentStatus">
  <successful-payment *ngSwitchCase="'success'"></successful-payment>
  <pending-payment *ngSwitchCase="'pending'"></pending-payment>
  <failed-payment *ngSwitchCase="'failed'"></failed-payment>
  <default-payment-status *ngSwitchDefault></default-payment-status>
</div>

With the built-in @switch statement, the code looks like:

@switch (paymentStatus) {
  @case ('success') { <successful-payment/> }
  @case ('pending') { <pending-payment/> }
  @case ('failed') { <failed-payment/> }
  @default { <default-payment-status/> }
}

The built-in control flow in Angular 17 facilitates notably improved type-narrowing within the individual branches of @switch, which is not achievable with the traditional \ngSwitch*.

Built-in for loops

The built-in for loop designed specifically for payments. This feature not only enriches the developer experience but also propels Angular's rendering speed to new heights!

The new way of writing for loops looks like this:

@for (transaction of payments; track transaction.id) {
  {{ transaction.amount }}
} @empty {
  No payment transactions found
}

Angular app often face speed issues because ngFor lacks a trackBy function. In the new syntax with @for, usage of track is mandatory for quick performance. It's simpler to use as it's just an expression, not a method in your component. @for also has a handy shortcut for empty collections using @empty. Behind the scenes, @for uses a better algorithm, making it up to 90% faster than ngFor according to community benchmarks!

Deferrable views

Angular 17 introduced a powerful mechanism utilising the new block syntax, allowing developers to significantly boost the speed of their apps. Deferrable views elevate performance and developer experience by enabling straightforward and powerful deferred loading with unparalleled ease.

Let's say you're developing an e-commerce platform, and you wish to implement deferred loading for the product reviews section. In the current approach, using ViewContainerRef it is complex to manage cleanups, to handle loading errors, to present skeleton loader, and more. Addressing these various situations often leads to the creation of intricate code, posing challenges in testing and debugging.

The code for implementing deferrable views in the new way appears as simple as the following:

@defer (on viewport) {
  <review-list />
} @placeholder {
  <!-- A placeholder content to show until the reviews load -->
  <img src="placeholder-image.png" />
}

The use of @placeholder in the code above is, of course, optional, for the sake of customisation. In the provided example, Angular first showcases the content within the placeholder block. As soon as it enters the viewport, Angular triggers the loading of the <review-list/> component. Once the loading is finished, Angular removes the placeholder and displays the fully rendered component on the web page.

This all happens during compile-time in Angular. The angular framework takes care of the complexity by identifying components, directives, and pipes within a @defer block. It then dynamically generates imports and manages the entire loading and state-switching process effortlessly, making deferred loading a breeze for developers.

There are more blocks for loading and error states, streamlining the management of various scenarios and Angular handles a lot of complexity behind the scenes, making the process seamless for you.

@defer (on viewport) {
  <review-list/>
} @loading {
  Loading…
} @error {
  Loading failed :(
} @placeholder {
  <img src="placeholder.png">
}

Deferrable views come with additional triggers for versatile lazy loading:

  • on idle: Load the block lazily when the browser is not engaged in heavy tasks.

  • on immediate: Initiate automatic deferred loading without blocking the browser.

  • on timer(<time>): Delay loading with a specified timer.

  • on viewport and on viewport(<ref>): In addition to triggering when in the viewport, you can specify a reference for an anchor element. Angular will lazily load and render the component when the anchor element becomes visible.

  • on interaction and on interaction(<ref>): Initiate deferred loading when the user interacts with a specific element.

  • on hover and on hover(<ref>): Trigger deferred loading when the user hovers over an element.

  • when <expr>: Define your own condition through a boolean expression.

Deferrable views also provide the ability to prefetch the dependencies ahead of rendering them. Adding prefetching is as simple as adding a prefetch statement to the defer block and supports all the same triggers.

@defer (on viewport; prefetch on idle) {
  <review-list />
}

In case of server side rendering, placeholder for the deferred views are rendered at the server side and the view is lazy loaded as client side rendering once the the angular framework loads the application and hydrates it to fully rendered html.

Build-in Control Flow Automatic Migration

It was designed to make upgrading super easy. It is automatically enabled in new Angular 17 projects. It's available as a developer preview feature, meaning you can explore its capabilities and provide feedback to the Angular team. However to try it in your existing applications, follow these simple migration steps:

  • Ensure you have Angular CLI version 17 or later installed globally

  • The following command can assist with the migration of existing projects, but it won't handle every aspect automatically.

      ng generate @angular/core:control-flow
    

    Here's a breakdown of what it does and what you'll still need to address:

    What it does:

    • Template updates: It primarily focuses on converting common directives \ngIf, ngFor, ngSwitch to the new built-in syntax if, for, switch* within your component templates.

    • Basic code adjustments: It might make minor modifications to related TypeScript code, such as updating import statements or variable names.

What it doesn't do:

  • Version check: You need to ensure you are currently on the angular version 17 or later. If not you may do it by using the ng update command as:

      ng update @angular/core @angular/cli
    
  • Manual checks: After the angular version upgrade, you'll need to manually review and test your migrated code to ensure everything works as expected before you proceed to run the ng generate command for control-flow.

  • Complex scenarios: It might not handle certain edge cases or custom flow logic perfectly, requiring manual intervention.

  • Additional configuration: You might need to adjust project settings or dependencies for full compatibility in your angular app.

You can utilise the built-in control flow with the latest language service, ensuring seamless integration with JetBrains products and proper formatting in Prettier.

TypeScript 5.2 Support

Angular 17 requires at least TypeScript 5.2. You cannot use earlier versions of TypeScript with Angular 17. Angular is committed to keeping pace with TypeScript releases, ensuring access to the latest language features. While Angular 17 supports TypeScript 5.2, hence it's generally recommended to use the latest stable TypeScript version for optimal compatibility and features.

There are several upgrade benefits of TypeScript to version 5.2:

  • TypeScript 5.2 offers up to 33% faster type checking for recursive types, potentially speeding up your development workflow for your web application

  • You can leverage new control flow declarations for cleaner code and ergonomic error handling with try...catch expressions in JSX

  • Automatic missing-comma insertions

  • Readonly arrays

  • The satisfies operator for type guards

  • Experimental await expressions in enum members

Revamped hybrid rendering experience

Angular 17 introduced an improved rendering experience, bridging server-side rendering (SSR) and static-site generation (SSG or pre-rendering) for developers. When creating a new Angular project with ng new, developers will now encounter a convenient prompt to enable SSR and SSG seamlessly. This change has been a long-anticipated improvement, and it's introduced now that we're confident in the SSR developer experience of Angular.

As an alternative, developers can enable SSR in new Angular 17 projects using the command:

ng new my-app --ssr

Hydration and Server Side Rendering

Hydration was introduced as developer preview in the previous versions as a new feature. Over the past six months, developers like you have embraced hydration in thousands of applications. Angular, marking a significant milestone announced the official exit of hydration from the developer preview phase. It's automatically enabled by default in all new apps using server-side rendering!

New @angular/ssr package

The Angular Universal repository has now been moved to the Angular CLI repository, emphasising the increased integration of server-side rendering into our broader tooling offerings. As of today, if you wish to add hybrid rendering support to your existing application, you can achieve this by running:

ng add @angular/ssr

Running this command will generate the server entry point, incorporate server-side rendering (SSR) and static-site generation (SSG) build capabilities, and enable hydration by default. Notably, @angular/ssr now offers the same functionality as @nguniversal/express-engine, which is presently in maintenance mode. If you're currently using express-engine, Angular CLI will seamlessly update your code to use @angular/ssr.

New Lifecycle Hooks

To boost the performance of Angular's SSR and SSG, there is need to move away from DOM emulation and direct DOM manipulations in the long run. Recognising the importance of element interactions throughout most applications' lifecycle, such as initialising third-party libraries or measuring element size, a set of new lifecycle hooks has been introduced:

  • afterRender — register a callback to be invoked each time the application finishes rendering

  • afterNextRender — register a callback to be invoked the next time the application finishes rendering

These hooks are triggered by the browser. It securely incorporates custom DOM logic directly into the angular components. This ensures a controlled environment for your specific DOM manipulations. Consider this example: If you want to instantiate a charting library, leverage the afterNextRender hook:

@Component({
  selector: 'my-chart-cmp',
  template: `<div #chart>{{ ... }}</div>`,
})
export class MyChartCmp {
  @ViewChild('chart') chartRef: ElementRef;
  chart: MyChart | null;

  constructor() {
    afterNextRender(() => {
      this.chart = new MyChart(this.chartRef.nativeElement);
    }, { phase: AfterRenderPhase.Write });
  }
}

Each hook, including afterNextRender, supports a phase value (e.g., read, write), which Angular utilises to schedule callbacks, minimising layout thrash and enhancing performance.

Vite and ESBuild the default for new projects

Enabling SSR in Angular from the beginning was made possible by significant changes in the Angular CLI's build pipeline!

In version 16, a developer preview of the ESBuild and Vite-powered build experience was introduced. Many developers dived into experimentation, and some enterprise partners reported impressive results, with up to a 67% improvement in build times for their apps! Today, it's exciting to announce that the new application builder has officially graduated from developer preview and is now the default for all new applications!

Additionally, the build pipeline for rendering has been fine-tuned. With SSR & SSG, you can now experience the speed boost in ng build as well as edit-refresh loop for ng serve.

Dependency injection debugging in DevTools

Last year, the Angular offered a sneak peek into the debugging features of Angular DevTools. Recently, they introduced new capabilities to:

  • See what components depend on

  • Understand the tree of injectors and how dependencies are resolved

  • Explore providers declared within injectors

Find more information on angular dev tools.

Standalone APIs from the start

Standalone components are a new feature that simplifies component architecture and offers potential performance benefits. Now, the ng generate command will create standalone new component, directive, and pipe.

The following command is a schematic that assists you in migrating your entire application to use standalone components.

ng generate @angular/core:standalone

Experimental view transitions support

Angular's experimental View Transitions API enables smooth DOM transitions. The router now directly supports this via the withViewTransitions feature. Configure it during bootstrap for seamless animated route transitions, leveraging the browser's capabilities. The withViewTransitions function provides optional configurations for added control, like skipping animations or customising animations with class adjustments on the document.

bootstrapApplication(App, {
  providers: [
    provideRouter(routes, withViewTransitions()),
  ]
});

Defer loading of the animations module

By using this feature, bundle can be compressed by size 60KBs (16KBs gzipped). Thanks to the community contribution from Matthieu Riegler. We can now lazily load the animation module using the following code:

import { provideAnimationsAsync } from '@angular/platform-browser/animations-async';

bootstrapApplication(RootCmp, {
  providers: [provideAnimationsAsync()]
});

Input value transforms

Generally, when working with components that receive boolean inputs, a common challenge arises when passing values using a certain syntax. Take, for instance, the ToggleComponent with the following definition:

@Component({
  selector: 'app-toggle',
  template: `...`,
})
export class ToggleComponent {
  @Input() isEnabled: boolean = false;
}

If you attempt to use it as <app-toggle isEnabled />, you might encounter an error stating "string is not assignable to boolean." To overcome this, you can utilise input value transforms by configuring the input decorator:

@Component({
  selector: 'app-toggle',
  template: `...`,
})
export class ToggleComponent {
  @Input({ transform: booleanAttribute }) isEnabled: boolean = false;
}

Here, booleanAttribute is a function imported from the @angular/core library. It's designed to transform string-based input values into boolean values before they're passed to component properties in your angular application.

Style and styleUrls as strings

Angular components offer the flexibility of supporting multiple stylesheets per component. Yet, in most cases, when styling components, a common approach is to create an array with a single element that points to inline styles or references an external stylesheet. In Angular 17, you can switch between using styles, styleUrls, and styleUrl based on whether you prefer defining inline styles, specifying an array of stylesheet URLs, or providing a single URL for the stylesheet, respectively.

Next steps on testing

The Angular team is currently exploring Jest to develop a solution that prioritises speed, flexibility, and user-friendliness. Simultaneously, there's experimentation with Web Test Runner, and there's an open pull request for the initial implementation. In the short term, the emphasis may shift towards Web Test Runner to assist projects eager to transition away from Karma.

Training Angular developers

The Angular team collaborated with SoloLearn, an interactive EdTech platform, to develop a new Angular training based on the recent Introduction to Angular course.

Conclusion

Angular 17 brings exciting improvements to web development. From faster performance to user-friendly features like deferrable views, it's a game-changer. As developers, we're empowered with tools that make our job smoother and more efficient. This update signals not just an upgrade but an invitation to a more enjoyable and impactful development experience. Let's embrace these changes and look forward to a future where Angular continues to lead the way in making web development better and more accessible for all.

0
Subscribe to my newsletter

Read articles from Trung Nguyen directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Trung Nguyen
Trung Nguyen