Master Angular 17.1 and 17.2
Tags: angular, typescript, signals, javascript
Published: 2024-02-27 12:00:37

---
title: Master Angular 17.1 and 17.2
published: true
tags: #angular #typescript #signals #javascript
canonical_url: https://www.angularaddicts.com/p/master-angular-17-1-and-17-2
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivrjit6gtghcdrs1ff6r.png
---
Since I published my [Master Angular 17 Study guide](https://www.angularaddicts.com/p/master-angular-17), the Angular team released two minor versions: Angular 17.1 and 17.2.

## 🎯Changes and new features

In this article, I list out the most important changes and new features, also share resources that will teach you how these new Angular features work:
- Model signal inputs
- View queries and component queries as signals
- `ngOptimizedImage`: Automatic placeholders
- `ngOptimizedImage`: Netlify image loader support
- Angular CLI: `clearScreen` option support
- Angular CLI: `define` option for declaring global identifiers

This article is also available on dev.to with better source code syntax highlighting.
### 📌Model signal inputs
PR: [Initial implementation of model inputs](https://github.com/angular/angular/pull/54252)

Angular 17.2 introduced model inputs. They based on writable signals and defines a input/output pair that can be used in two-way bindings. In the example below, the signals in the two components always have the same value, and you can increase this value by pressing on of the buttons:

```ts
@Component({
  selector: 'app-counter',
  standalone: true,
  template: `<button (click)="increase()">Counter's button: {{ value() }}</button>`,
})
export class CounterComponent {
  value = model.required<number>();
  increase() {
    this.value.update((x) => x + 1);
  }
}

@Component({
  selector: 'app-wrapper',
  standalone: true,
  imports: [CounterComponent],
  template: `<app-counter [(value)]="count" />
    <button (click)="increase()">Wrapper's button: {{ count() }}</button>`
})
export class WrapperComponent {
  count = signal(0);
  increase() {
    this.count.update((x) => x + 1);
  }
}
```

We can also bind an input element's value to a writable signal by two-way data binding, using the 'banana in the box' syntax `[(ngModel)]`:

```ts
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    FormsModule,
  ],
  template: `
<textarea
  [(ngModel)]="promptValue"
></textarea>`
})
export class AppComponent {
  promptValue = signal('');
}
```

### 📌View queries and component queries as signals
PR: [feat(core): expose queries as signals](https://github.com/angular/angular/pull/54283)

With this improvement, we can query elements from the component's template as signals: there are new `viewChild()`,  `viewChildren()`,  `contentChild()` and  `contentChildren()` functions that return Signals. These are signal based versions of the `@viewChild`,  `@viewChildren`,  `@contentChild` and  `@contentChildren` decorators:

```ts
@Component({
  selector: 'app-vc-query-as-signal',
  standalone: true,
  template: `
    <button (click)="show()">Show</button>
    @if(visible()) {
      <div #id1>Hi!</div>
    }`,
})
class VcQueryAsSignalComponent {
  visible = signal(false);
  divEl = viewChild<ElementRef<HTMLDivElement>>('id1'); // 👈
  effectRef = effect(() => {
    console.log(this.divEl());
  });
  show() {
    this.visible.set(true);
  }
}

// First message on the console: undefined
// The user clicks on the button
// Second message on the console: _ElementRef {nativeElement: div}

```

### 📌ngOptimizedImage: Automatic placeholders, Netlify image loader support
Official docs: [Automatic placeholders](https://angular.dev/guide/image-optimization#automatic-placeholders)
PR: [feat(common): add Netlify image loader](https://github.com/angular/angular/pull/54311)
PR: [feat(common): add placeholder to NgOptimizedImage](https://github.com/angular/angular/pull/53783)

NgOptimizedImage can automatically display a low-res placeholder when using an image CDN.
The Angular team has also added the `provideNetlifyLoader` preconfigured loader to support the Netlify image CDN. 

```ts
@Component({
  selector: 'app-image',
  standalone: true,
  imports: [NgOptimizedImage],
  template: `
    <p>Responsive image:</p>
    <!-- 30 x 30 url encoded image as a placeholder 👇 -->
    <img ngSrc="assets/lamp.jpeg" style="max-width: 1024px" [placeholder]="data:@file/jpeg;base64,..." />
  `,
})
export class ImageComponent {
}

// app.config.ts

export const appConfig: ApplicationConfig = {
  // provider for the Netlify image CDN 👇
  providers: [provideNetlifyLoader('https://yoursite.netlify.app/')],
};
```
### 📌Angular CLI: clearScreen option support
PR: [a957ede build: update angular](https://github.com/angular/angular-devkit-build-angular-builds/commit/f5cf028cef1051d329299d347517ea443b6bf088)

Angular can clear the screen before each re-build. You can enable this feature in `angular.json`, by setting the `clearScreen` builder option to `true` (it's `false` by default):

```typescript
// angular.json

{
  "projects": {
    "ng172": {
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            // 👇 clear the screen before each re-build
            "clearScreen": true,
            // ...            
```
### 📌Angular CLI: 'define' option for declaring global identifiers
PR: [feat(@angular-devkit/build-angular): add define build option to application builder](https://github.com/angular/angular-cli/commit/7f57123fd40b345d7880cb9e2eccd4757c0fb6ee)

The `application` builder supports the `define` option for declaring global identifiers. As these identifiers declared in `angular.json`, not in a `.ts` support, we can declare it for typescript using a `declare const` statement in `src/types.d.ts`.  We can use these identifiers as an alternate to the environment files in the future.

```ts
@Component({
  template: `
    Text: {{ CONSTANT_IN_ANGULAR_JSON.text }}, 
    Number:{{ CONSTANT_IN_ANGULAR_JSON.number }}`,
})
export class GlobalIdentifierComponent {
  CONSTANT_IN_ANGULAR_JSON = CONSTANT_IN_ANGULAR_JSON;
}

// angular.json

{
  "projects": {
    "ng172": {
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "define": {
              // the value must have a valid JSON syntax 👇
              "CONSTANT_IN_ANGULAR_JSON": "{ 'text': 'This constant is defined in angular.json', 'number': 1 }"
            },
            // ...
            
// src/types.d.ts

declare const CONSTANT_IN_ANGULAR_JSON: { text: string; number: number };
```

## 👨‍💻About the author

My name is [Gergely Szerovay](https://www.linkedin.com/in/gergelyszerovay/), I work as a frontend development chapter lead. Teaching (and learning) Angular is one of my passions. I consume content related to Angular on a daily basis — articles, podcasts, conference talks, you name it.

I created the Angular Addict Newsletter so that I can send you the best resources I come across each month. Whether you are a seasoned Angular Addict or a beginner, I got you covered.

Next to the newsletter, I also have a publication called [Angular Addicts](https://angularaddicts.com/). It is a collection of the resources I find most informative and interesting. Let me know if you would like to be included as a writer.

Let’s learn Angular together! [Subscribe here](https://www.angularaddicts.com/) 🔥

Follow me on [Substack](https://www.angularaddicts.com/), [Medium](https://medium.com/@GergelySzerovay), [Dev.to](https://dev.to/gergelyszerovay), [Twitter](https://twitter.com/GergelySzerovay) or [LinkedIn](https://www.linkedin.com/in/gergelyszerovay/) to learn more about Angular!