Angular 17.2: New features

Updated: 2024-02-15

Release date: 2024-02-14
Official release notes: list of changes 17.2.0

Official blog about Angular 17.2: Angular v17.2 is now available

Here a list of what can be useful in the daily activity of a developer. I will add some extra information.
Compiler improvement and bugfixes are not included.

Core: model input #54252

A new member of the signal family is coming: model() returns a writable signal that can be used for two-ways bindings. model (export interface ModelSignal<T> extends WritableSignal<T>) it's currently in developer preview.

It's a writeable signal for a directive/component model field. Whenever its value is updated, it emits to the output.

This example comes directly from the Angular GitHub, I will update it in the next days:

@Directive({ 
  selector: 'counter', 
  standalone: true, 
  host: { 
    '(click)': 'increment()', 
  } 
}) 
export class Counter { 
  value = model.required(0); 
 
  increment(): void { 
    this.value.update(current => current + 1); 
  } 
} 
 
@Component({ 
  template: `<counter [(value)]="count"/> The current count is: {{count()}}`, 
}) 
class App { 
  count = signal(0); 
} 

Here you can find a quick intro to the signals.

Core: Expose queries as signals #54283

Now the decorators @ContentChild , @ContentChildren, @ViewChild, @ViewChildren

They have their signal equivalent: contentChild, contentChildren, viewChild, viewChildren.

The signal queries support required (example from Angular test code):

 @Component({ 
    standalone: true, 
    template: `<div #el></div>`, 
}) 
class AppComponent { 
    divEl = viewChild.required<ElementRef<HTMLDivElement>>('el'); 
    foundEl = computed(() => this.divEl() != null); 
} 

The decorators queries where resolving before ngAfterContentInit(), the new signal queries resolve after the creation mode and before the change detection runs.

The queries can be used for components:

childrenComponents = viewChildren(MySimpleComponent); 
found = computed(() => this.childrenComponents.length) 
effect(() => console.log(this.childComponents)) 

Placeholder for NgOptimizedImage #53783

This feature is interesting if your app is accessible on the web and has a lot or big images. It's not really relevant for enterprise development.

Adding the placeholder attribute to an image will display a placeholder during the loading of the image.
For this your image needs to be stored by a CDN / image host that allows image resizing.
Using an Image Loader Angular will initially load a small version in low resolution of your image and show it, subsequently will load the full image.
This placeholder will be blurred using CSS when the image loads.

<img ngSrc="myBlogPicture.jpg" width="600" height="300" placeholder> 

Without an image loader (recommended solution) you can use a base 64 image with a data url

<img ngSrc="myBlogPicture.jpg" width="600" height="300" placeholder="data:image/png;base64,..."> 

The placeholder image is 30px wide but can be changed: providers: [ { provide: IMAGE_CONFIG, useValue: { placeholderResolution: 200 } }, ],

Other options are available (blurring etc.). We will wait the release to add some information.

Angular Image Service loaders

Here the list of the loaders from the Angular Documentation, Netlify has been added with 17.2.rc0:

Image ServiceAngular APIDocumentation
Cloudflare Image ResizingprovideCloudflareLoaderDocumentation
CloudinaryprovideCloudinaryLoaderDocumentation
ImageKitprovideImageKitLoaderDocumentation
ImgixprovideImgixLoaderDocumentation
NetlifyprovideNetlifyLoaderDocumentation

CLI: clear the screen before each build

Nice little feature, you can now ask Angular to clear the screen every time the application is re-built:

In your angular.json you can set clearScreen to true (default is false).

"architect": { 
  "build": { 
    "builder": "@angular-devkit/build-angular:application", 
      "options": { 
        "clearScreen": true 
      } 

Behind the scenes it simply calls : console.clear(); every time a build is started.

CLI: the builder can replace global identifiers

Angular introduced the define option in the compiler, this behaves like DefinePlugin of esbuild.

With this feature is possible to replace global identifiers with constant expressions. During the build phase, Angular will replace the identifiers with the pre-defined constants.

You can find the commit with the description here: add define option to application builder.

Here an example. In angular.json inside of build you can add define: define?: {[key: string]: string;};

"architect": { 
  "build": { 
    "define": { 
      "MY_NUMBER": "7", 
      "MY_NAME": "'Marco'" 
  }, 

It's recommended to declare a type to avoid issues with the IDE, in your [application]\src\types.d.ts folder:

declare const MY_NUMBER: number; 
declare const MY_NAME: string; 

You can use these constants in your code, e.g. in a component:

export class MyComponent { 
  myName = MY_NAME; 
  protected readonly MY_NUMBER = MY_NUMBER; 

During the build the constant MY_NAME and MY_NUMBER will be replaced with 'Marco' and 7.

In the template:

My Name is: {{myName}} 
My Number is: {{MY_NUMBER}} 

Angular Material 3 (Experimental support)

Material 3 is coming to Angular, you can already 'play' with it or preparing yourself with the theory Material Design 3 by Google.
The implementation it's maybe targeting Angular v. 18.

Here the official blog post: Material 3 Experimental Support in Angular 17.2

What's new in version 17.1

Angular 17.1 is the last official version released on January 17th, 2024.

You can find a list of changes (more than 10) relevant for developers here: https://marco.dev/angular-17-1-features


You could be interested in

Right click context menu with Angular

Right click custom menu inside dynamic lists with Angular Material
2020-05-31

Angular 17.3: New features

New features introduced in Angular 17.3
2024-02-01

Angular 17.1: New features

New features introduced in Angular 17.1
2024-01-26
Fullstack Angular / Java application quick start guide.
WebApp built by Marco using SpringBoot 3.2.4 and Java 21. Hosted in Switzerland (GE8).