DEV Community

Cover image for Episode 24/07: Angular 17.2, optional RxJs
ng-news for This is Angular

Posted on

Episode 24/07: Angular 17.2, optional RxJs

We got Angular 17.2 and a written confirmation along with an explanation that the Angular team wants to make RxJs optional in the upcoming years.

Angular 17.2

Angular 17.2 is out. Due to new features, a component is now almost a Signal Component. We still require zone.js or an EventEmitter, but quite a lot of the "Component API' works now with a Signal.

model()

The model function creates a writable Signal, presenting itself to the parent component as two-way binding.

Before:

@Component({
  selector: 'app-tags',
  template: `<h3>Select Tags</h3>
    @for (tag of existingTags; track tag) {
      <button class="p-4 border-2 cursor-pointer" (click)="toggleTag(tag)">
        {{ tag }}
      </button>
    }`,
  standalone: true,
})
export class TagsComponent {
  existingTags = getTags();
  @Input() tags: string[] = [];
  @Output() tagsChange = new EventEmitter<string[]>();
  toggleTag(tag: string) {
    if (this.tags.includes(tag)) {
      this.tags = this.tags.filter((value) => value !== tag);
    } else {
      this.tags = [...this.tags, tag];
    }
    this.tagsChange.emit(this.tags);
  }
}
Enter fullscreen mode Exit fullscreen mode

After:

@Component({
  selector: 'app-tags',
  template: `<h3>Select Tags</h3>
    @for (tag of existingTags; track tag) {
      <button class="p-4 border-2 cursor-pointer" (click)="toggleTag(tag)">
        {{ tag }}
      </button>
    }`,
  standalone: true,
})
export class TagsComponent {
  existingTags = getTags();
  tags = model<string[]>([]);
  toggleTag(tag: string) {
    const tags = this.tags();
    if (tags.includes(tag)) {
      this.tags.update((tags) => tags.filter((value) => value !== tag));
    } else {
      this.tags.update((tags) => [...tags, tag]);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

"Banana Box" and Writable Signal

Separated from the new model function, the banana box syntax now supports also writable Signals:

Before:

@Component({
  selector: 'app-tags-selector',
  template: `
    <app-tags [(tags)]="tags"></app-tags>
    <p>Selected Tags: {{ prettyTags }}</p>
  `,
  standalone: true,
  imports: [TagsComponent, JsonPipe],
})
export class TagsSelectorComponent {
  tags: string[] = [];
  get prettyTags() {
    return this.tags.join(', '); // performance issue
  }
}
Enter fullscreen mode Exit fullscreen mode

After:

@Component({
  selector: 'app-tags-selector',
  template: `
    <app-tags [(tags)]="tags"></app-tags>
    <p>Selected Tags: {{ prettyTags() }}</p>
  `,
  standalone: true,
  imports: [TagsComponent, JsonPipe],
})
export class TagsSelectorComponent {
  tags = signal<string[]>([]);
  prettyTags = computed(() => this.tags().join(', '));
}
Enter fullscreen mode Exit fullscreen mode

Queries

As planned, we also have signal-based alternatives for ViewChild and ContentChild. They are also simple functions and go without a decorator.

These features are still in developer preview, but as soon as they go production-ready, they're no longer an alternative but the preferred way to write modern Angular applications.

The model and the query come in a variation with a required function. The required function is something we already saw with the Signal Input in 17.1.

Before:

@Component({
  template: `
    <form>
      <input [(ngModel)]="user.firstname" name="firstname" />
      <input [(ngModel)]="user.lastname" name="lastname" />
    </form>
  `,
  standalone: true,
  imports: [FormsModule],
})
export class IntroductionComponent implements AfterViewInit {
  @ViewChild(NgForm) ngForm: NgForm | undefined;
  ngAfterViewInit(): void {
    if (!this.ngForm) {
      console.error('form is not available');
      return;
    }
    this.ngForm.form.valueChanges.subscribe(console.log);
  }
  user = { firstname: 'Konrad', lastname: 'Huber' };
}
Enter fullscreen mode Exit fullscreen mode

After:

@Component({
  template: `
    <form>
      <input [(ngModel)]="user.firstname" name="firstname" />
      <input [(ngModel)]="user.lastname" name="lastname" />
    </form>
  `,
  standalone: true,
  imports: [FormsModule],
})
export class IntroductionComponent {
  ngForm = viewChild.required(NgForm);
  constructor() {
    effect(() => this.ngForm().form.valueChanges.subscribe(console.log));
  }
  user = { firstname: 'Konrad', lastname: 'Huber' };
}
Enter fullscreen mode Exit fullscreen mode

Required removes the undefined from the Signal's underlying type. We are switching from a potential compilation to a runtime error.

It is our responsibility that we don't directly access it too early. For the queries, we can use afterNextRender.

In general, we are safe if we access the Signal in the template or via a computed or effect.

Other features in 17.2 are the support for Bun, an alternative to Node.js, and the NgOptimizedImage, which supports loading images from Netlify. And the DevTools also received improvements for SSR. We have experimental support for Material 3.

Further Reading

Angular v17.2 is now available. We rarely write blog posts about minor… | by Minko Gechev | Feb, 2024 | Angular Blog

We rarely write blog posts about minor releases, but today we have a few surprises for you — experimental support for Material 3, signal…

favicon blog.angular.io

Material 3 Experimental Support in Angular 17.2 | by Miles Malerba | Feb, 2024 | Angular Blog

We’re thrilled to announce that Angular 17.2 features experimental support for Material 3 theming in Angular Material.

favicon blog.angular.io

What’s new in Angular 17.2? | Ninja Squad

Angular 17.2 is out!

favicon blog.ninja-squad.com

Angular 17.2 Is Out: What's New?

A complete guide to the brand new Angular 17.2 features, including: the new signal-based view queries viewChild, viewChildren, contentChild, and contentChildren, as well the new model() two-way binding mechanism.

favicon blog.angular-university.io

Optional RxJs

Next to Angular 17.2, we have, for the first time, written confirmation that the Angular team will make RxJs optional. That will require huge changes to the API, which will gradually happen over multiple major releases.

Top comments (2)

Collapse
 
jangelodev profile image
João Angelo

Hi ng-news,
Your tips are very useful
Thanks for sharing

Collapse
 
ng_news profile image
ng-news

Thanks again :)