Matthew Tyson
Contributing writer

The best new features in Angular 17: A kinder, faster Angular

how-to
Dec 06, 20238 mins
Development ToolsJavaScriptSoftware Development

Featuring a slew of enhancements, Angular 17 makes it harder than ever to pick a front-runner among JavaScript frameworks.

thumbs up positive attitude congratulations happy employees staff

Angular is one of the most storied front-end web frameworks, and it has gone through significant changes since its initial release—including the complete rewrite that transformed it into a reactive framework in the vein of React. Angular today is a powerful system with some great ideas, like reactive eventing throughout and a robust dependency injection system. This article is an overview of improved features in Angular 17. As you’ll see, the latest release seeks to improve developer experience, optimize performance, and funnel the power of Angular into a more approachable package. Let’s take a look.

Non-technical improvements

Angular has a new look and feel and a new site angular.dev (analogous to React’s new react.dev). In addition to its slick look, Angular’s new site sports an interactive tutorial that lets you write in-browser Angular code and a Playground that supports the latest version.

The Angular blog has a good roundup of these non-technical changes, including the new Angular logo. In general, the ongoing work at Angular makes it clear that the team is fully committed to doing whatever it takes to make the framework a viable modern option. All that work appears to be coming together and yielding dividends in Angular 17. 

A word about migration

Angular 17 gives all evidence of a carefully planned and executed operation that prioritizes migration support for existing projects. The upshot is that developers should breathe easy. The Angular command-line is very smart about automatic and opt-in migrations. In general, the framework makes it easy for projects to painlessly update to the latest version and take advantage of new features.

Technical updates in Angular 17

  • New looping syntax
  • If-then-else
  • Switch
  • Block directives
  • Deferred rendering
  • SSR and SSG
  • New build system
  • Improved debugging for dependency injection

New looping syntax

Iterating over collections is a JavaScript UI pet peeve of mine. It’s something you know you’re going to have to do a lot, and it would be nice if it had a syntax that was simple and easy to handle, especially with increasing complexity. In light of this, it is promising that Angular 17 introduces a simplified syntax, @for, for dealing with loops.

You can see a live example of the new looping capability in the Angular playground. In this example, we loop over an array of to-do items:


@for (todo of todos; track $index) {...}

That’s pretty succinct. We expose the todo variable for each element of todos, and we “track” the built-in $index field. The $index variable will show the automatically generated row number for the element (there are other implicit variables like $first, $odd, and $count). You can also use a field on the elements you want to track:


@for (todo of todos; track todo.id) {...}

In this new syntax, the track variable is required, by design. In previous incarnations, the tracking variable was optional, which led to performance degradation. The tracking key on a loop enables the rendering engine to optimize the list display and know what has changed. 

Along with other under-the-hood performance enhancements, the new loop syntax with required index keys is reporting major performance gains.

If-then-else

Angular 17 also brings new looping syntax to improve if handling. In the previous playground example, you can see the $if syntax in action:


@if (todo.done) {
  <s>{{ todo.text }}</s>
} @else {
  <span>{{ todo.text }}</span>
}

Again, the syntax has eliminated the obfuscating markup and given us a straightforward JavaScript way of saying what we want to do. The if handling is simple enough to retain without much thought, and even the @else handling is low overhead. @else if is also supported.

Switch

Angular’s new switch syntax applies typical JavaScript syntax to templates:


@switch (condition) {
  @case (caseA) {
    <span>Case A.</span>
  }
  @case (caseB) {
    <span>Case B.</span>
  }
  @default {
    <span>Default case.</span>
  }
}

Block directives

@for, @if, and @switch are new “block” directives. They allow us to inject chunks of markup into the template using JavaScript syntax. These new directives replace previous approaches like *ngIf. You can still use *ngIf and other older syntax, and an automated command in the CLI lets you change over to the block syntax: $ ng generate @angular/core:control-flow.

Deferred rendering

Angular now supports deferred rendering via the block syntax. This gives you a simple and powerful mechanism for defining ways to tell the browser what to display along with instructions for doing it in a non-linear way. The Angular 17 tutorial has some good examples of using @defer.

Here’s an example of the simplest @defer:


@defer {
  <span>My deferred content</span>
}

This tells the browser to render the rest of the page first, and then the deferred content. It’s a very simple syntax for the times when you want to avoid front-loading everything.

You can also provide @placeholder and @loading blocks:


@defer {
 <span>My deferred content</span>
} @placeholder {
 <span>Placeholder content</span>
} @loading {
 <span>Loading deferred content...</span>
}

Placeholder and loading both provide a static layout for the coming content, @placeholder first, then @loading.

Several different strategies are supported by @defer out of the box, like viewport (when the user scrolls it into view), idle (browser is idle), interaction (user interacts with the element), and hover (pointer hovers on element). Here’s an example using hover:


@defer (on hover) {
 <span>My hover content</span>
}

There’s even a @defer(when <expression>) that takes a promise, so you can really defer on any conceivable situation. All in all, the new @defer mechanism is impressive. Deferred rendering is usually persnickety and really interferes with the flow of a developer’s thought and the resulting code. This latest version of Angular makes it easy.

Note that @defer is still a developer preview in Angular 17, but is considered production ready.

SSR and SSG

In addition to the improvements you’ve seen so far, the Angular team is making a real effort to improve server-side rendering and generation (SSR/SSG). Angular has developed an integrated SSR experience that will supersede the previously used Express/Angular setup. Much of the work also is devoted to improving the way the user interface “hydrates.”

A hot topic among reactive frameworks, hydration essentially determines how best to take the elements that are rendered on the server and ship them over to the client, and then turn them into living reactive components. Hydration involves the way deferred components are rendered, and the work is ongoing. SSR engines are always looking for the cleverest way to ship the smallest package of data for every segment, and then minimize the amount of work the front-end does to enable them. 

You can use the new Angular SSR set up now, and the CLI generator includes support for it. When you use the ng new command, it will give you the option to include SSR:


$ ng new
Node.js version v21.2.0 detected.
Odd numbered Node.js versions will not enter LTS status and should not be used for production. For more information, please see https://nodejs.org/en/about/previous-releases/.
? What name would you like to use for the new workspace and initial project? iw-ng-17
? Which stylesheet format would you like to use? CSS
? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? Yes

Now if you run $ng serve, you’ll be served a simple SSR site. Looking at the directory created, you’ll see the files for both sides of the application, including main.server.ts and main.ts.

New build system

Angular has joined the Vite movement, and Angular 17 uses Vite with Esbuild as its build engine. This was a required change for underpinning the new SSR system. For developers, the main impact is that it’s faster, including for serving and updating in dev mode.

Improved debugging for dependency injection

One of my favorite features of Angular is its dependency injection system, which lets developers wire together application components using IoC, or inversion of control. Essentially, all we have to do is name our components and then inject them together, which makes for more flexible design.

Angular 17 introduces more powerful debugging support for this system, so it is more obvious what is happening in the debug console. Work is ingoing here as the team looks to make dependency injection even easier to visualize and understand at runtime.

Conclusion

It is exciting to see all the work happening on Angular. The team clearly has a lot of determination and energy; enough to take on even epic projects that span years and require fundamental changes to how the framework operates. Many of those commitments are just now starting to bear fruit, and we can anticipate even more interesting improvements in Angular 18, due for release in May 2024. 

Angular 17 makes it harder than ever to pick a clear front-runner among JavaScript frameworks—and that’s a good thing.