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

19 1

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!

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

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

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up