DEV Community

Cover image for Master Angular 17.1 and 17.2
Gergely Szerovay for This is Angular

Posted on • Originally published at angularaddicts.com

Master Angular 17.1 and 17.2

Since I published my Master Angular 17 Study guide, 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

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:

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

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)]:

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

📌View queries and component queries as signals

PR: feat(core): expose queries as signals

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:

@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}

Enter fullscreen mode Exit fullscreen mode

📌ngOptimizedImage: Automatic placeholders, Netlify image loader support

Official docs: Automatic placeholders
PR: feat(common): add Netlify image loader
PR: feat(common): add placeholder to NgOptimizedImage

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.

@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/')],
};
Enter fullscreen mode Exit fullscreen mode

📌Angular CLI: clearScreen option support

PR: a957ede build: update angular

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):

// angular.json

{
  "projects": {
    "ng172": {
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            // 👇 clear the screen before each re-build
            "clearScreen": true,
            // ...            
Enter fullscreen mode Exit fullscreen mode

📌Angular CLI: 'define' option for declaring global identifiers

PR: feat(@angular-devkit/build-angular): add define build option to application builder

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.

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

👨‍💻About the author

My name is Gergely Szerovay, 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. 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 🔥

Follow me on Substack, Medium, Dev.to, Twitter or LinkedIn to learn more about Angular!

Top comments (2)

Collapse
 
artydev profile image
artydev

Thank you :-)

Collapse
 
jangelodev profile image
João Angelo

Hi Gergely Szerovay ,
Your tips are very useful
Thanks for sharing