DEV Community

Cover image for Ng-News 24-47: Angular 19
ng-news for This is Angular

Posted on

Ng-News 24-47: Angular 19

Angular 19 has been released!

Standalone by default

First things first—when you update, make sure to run ng update or nx migrate, but avoid using the native npm install command.

Don’t be surprised if the update script changes all your components. Standalone is now the default.

The update script removes standalone: true from all components, while NgModule-based components will now have standalone: false added.

Utility Functions for Signals

linkedSignal()

With linkedSignal, you can clone an existing Signal. You can modify the clone, but those changes won’t affect the original. However, if the original Signal updates, its value will overwrite the clone.

This is perfect for:

  1. Template-driven forms, where you need a working copy of a Signal.

Pre Angular 19:

export class CustomerComponent {
  // original
  customer = input.required<Customer>();

  // working copy
  formCustomer: Customer | undefined = undefined;

  // synchronization
  #syncEffect = effect(() => {
    this.formCustomer = this.customer();
  })
Enter fullscreen mode Exit fullscreen mode

Angular 19:

export class CustomerComponent {
  // original
  customer = input.required<Customer>();

  // working copy
  formCustomer = linkedSignal(this.customer)
}
Enter fullscreen mode Exit fullscreen mode
  1. Managing a state linked to a parent Signal. For example, when a parent component passes down an ID to a child component, and the child’s state needs to reset when the parent’s Signal changes.

Pre Angular 19

export class BasketComponent {
  protected readonly selectedProductId = input.required<number>();
  protected readonly amount = signal(1);

  readonly #resetEffect = effect(
    () => {
      this.selectedProductId();
      this.amount.set(0);
    },
    { allowSignalWrites: true },
  );
}
Enter fullscreen mode Exit fullscreen mode

Angular 19

export default class BasketComponent {
  protected readonly selectedProductId = input.required<number>();

  protected readonly amount = linkedSignal({
    source: this.selectedProductId,
    computation: () => 1,
  });
}
Enter fullscreen mode Exit fullscreen mode

linkedSignal is in developer preview. While the functionality is stable, breaking changes within a major version are still possible.

resource() & rxResource()

The resource function addresses Signals where the value comes from an asynchronous task, such as an HTTP request. Its standout feature is managing race conditions by automatically canceling HTTP requests — without using RxJS.

Pre Angular 19

export class EditCustomerComponent {
  readonly #customerService = inject(CustomerService);

  readonly id = input.required({ transform: numberAttribute });
  readonly customer = signal<Customer | undefined>(undefined);

  readonly #loadEffect = effect(() => {
    this.#customerService.findById(this.id()).subscribe((customer) => {
      this.customer.set(customer);
    });
  });
}
Enter fullscreen mode Exit fullscreen mode

Angular 19

export class EditCustomerComponent {
  readonly #customerService = inject(CustomerService);

  readonly id = input.required({ transform: numberAttribute });
  readonly customer = resource({
    request: () => this.id(),
    loader: (options) => {
      const id = options.request;
      return this.#customerService.fetchById(id, options.abortSignal);
    },
  });
}
Enter fullscreen mode Exit fullscreen mode

Additionally, there’s an RxJS-powered version called rxResource.

Both functions are still experimental, so breaking changes are likely.

However, this marks a fundamental milestone, showcasing Angular’s direction with Signals and its "optional RxJS" approach.

Incremental Hydration

Incremental Hydration allows parts of your template to hydrate based on specific triggers.

For example:

  • When a user interacts with it.
  • After a delay.
  • Or never
@Component({
  selector: 'app-edit',
  template: `
    <div class="flex">
      <div class="flex-1 p-4">
        <app-full-text #editor [(content)]="munichDescription" />
      </div>
      <div class="flex-1 prose p-4 mx-auto">
        @defer (hydrate never) {
          <!-- Component with heavy dependency to marked library -->
          <app-markdown-renderer [markdown]="munichDescription()"/>
        }
      </div>
    </div>`
})
export class EditComponent {}
Enter fullscreen mode Exit fullscreen mode

This feature comes from Angular’s collaboration with Wiz, Google’s internal framework used in Gmail, Google Search, and other performance-intensive applications.

While Incremental Hydration might not be relevant for all use cases — such as internal applications — it opens Angular to a completely new group of developers.

These are developers who previously relied on frameworks like Next.js, Remix, or Qwik to build interactive websites that load instantly and are efficient in terms of bundle size.

More Information

For more information, check out:
The official release video on YouTube.

The Q&A session with Mark and Jeremy from the Angular team.

The Angular blog post

Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Nov, 2024 | Angular Blog

In the past two years we doubled down on our investment in developer experience and performance — in every single release we’ve been…

favicon blog.angular.dev

Top comments (1)

Collapse
 
spock123 profile image
Lars Rye Jeppesen • Edited

Careful for mono repos with multiple projects

There is a language service issue which marks the missing standalone flag as an error. Many people reported it, us included.

Other than that, v19 is an awesome release.