Ng-News 26/15: Angular 22

The main stories this week are the stable release of Angular 22 resources and Signal Forms, along with fresh dependency injection APIs like @Service and injectAsync. We also cover debounced(), Vitest migration support, ChangeDetectionStrategy.Eager, WebMCP, community articles, and the ng-neat recovery.
Stable resources and Signal Forms
Angular 22 has arrived. The most notable development is that resource and Signal Forms have moved out of experimental status. There is plenty more in this release, but these two items take center stage.
Resources — namely the trio of resource(), rxResource(), and httpResource() — were first introduced during Angular 19. They saw substantial modifications in Angular 20, and in Angular 21 the snapshot feature was added. Throughout that period, resources remained experimental; after nearly 1.5 years, they have now achieved stable status.
The same trajectory applies to Signal Forms, but on a quicker timeline. They debuted in Angular 21 and are also stable now, meaning they are no longer in developer preview.
In many ways, these are capabilities we are already familiar with, and quite a few of us have been using them successfully.
It is also worth mentioning that @angular/aria, the headless design system, has reached stability as well.
@Service, injectAsync, and debounced()
Yet there are also brand-new features to look at.
First up is the @Service decorator. On one hand, it serves as a shorthand for @Injectable({ providedIn: 'root' }); on the other, it discourages constructor-based dependency injection. You are guided to use the inject function instead, and a dedicated migration is provided via ng generate @angular/core:inject.
@Service()
export default class NewsletterClient {
private httpClient = inject(HttpClient);
send(email: string): Observable<boolean> {
return this.httpClient.post<boolean>(
'http://some.host.com/newsletter/subscribe',
{ email },
);
}
}
Another DI addition is the asynchronous injector. The value returned by injectAsync is not the service instance itself — you invoke it when you actually need the service and then await the result. Why is this useful? The reasoning mirrors that behind lazy loading in the router: we only load things when they are genuinely required.
export class NewsletterPage {
private readonly newsletterModel = signal({ email: '' });
private readonly newsletterClient = injectAsync(
() => import('./newsletter-client'),
);
protected readonly newsletterForm = form(
this.newsletterModel,
(path) => { },
{
submission: {
action: async () => {
const client = await this.newsletterClient();
client.send(this.newsletterModel().email)
},
},
},
);
}So injectAsync is not meant for immediate service access but rather for later moments, such as a user click or other subsequent events. The service must be providedIn: 'root', so pairing it with the new @Service decorator is a sensible approach.
There is also a debounced function. You supply a signal and a debounce duration, and you receive a resource in return. Debouncing works as follows: when the signal's value changes, the derived resource waits for the specified time span before adopting the new value. If no further updates arrive within that window, the resource takes on the value; if changes do occur, the debounce timer resets.
Since every signal has an initial value, debouncing does not apply to that first value.
@Component({
selector: 'app-debounced',
template: `Value {{ debouncedCounter.value() }}`,
})
export class DebouncedPage {
protected readonly counter = signal(1);
protected readonly debouncedCounter = debounced(this.counter, 600);
constructor() {
setTimeout(() => this.counter.update((v) => v + 1), 500);
setTimeout(() => this.counter.update((v) => v + 1), 1_000);
setTimeout(() => this.counter.update((v) => v + 1), 1_500);
effect(() => {
console.log(`value updated ${this.debouncedCounter.value()}`);
});
}
}Note that debounced() remains experimental, while @Service and injectAsync are not.
- Angular 22: Key Features and Changes
- Angular 22: The Most Important New Features at a Glance - ANGULARarchitects
Vitest and change detection
Angular 21 introduced Vitest as the new default testing framework. Migration was not straightforward initially because many developers relied on fakeAsync or waitForAsync for handling asynchronous tasks in tests. With Angular 22, those utilities work again — but keep in mind that fakeAsync and waitForAsync depend on zone.js. So if you are planning to go zoneless, or have already made that move, these are not viable options.
When you run ng update, components that are not using OnPush will receive ChangeDetectionStrategy.Eager. This is the new alias for the old Default value, because default does not mean OnPush. On the topic of zoneless, if migration is on your radar, staying with zone.js while converting all components to OnPush as an interim step is a solid strategy.
WebMCP
In the realm of AI, experimental support for WebMCP has been added. This allows an agent to connect to your web application and execute specific tool calls. As an Angular developer, you expose service calls with descriptions and other metadata; if the browser supports it, the agent can invoke them. This removes the need for the agent to read and manipulate the DOM directly.
WebMCP is still under active development, and we can anticipate more news on this front. There is also a feature that sets up forms for WebMCP.
Community content
As usual, the community has been busy. There is a release video, a release blog, and Mark Thompson, Angular's DevRel, appeared as a guest on the Angular Plus Show.
For this episode, we also drew on blog posts from Cedric Exbrayat at Ninja Squad, Manfred Steyer at Angular Architects, and Mateusz Stefańczyk at House of Angular.
ng-neat GitHub
Finally, an important piece of news. Over the past weekend, the well-known ng-neat organization was removed from GitHub. This organization hosted widely used libraries such as Elf for state management and Spectator for testing. Prior to that, members of the organization had also been removed. As of now, the reasons are unclear, since there has been no official statement from the owner.
The key point is that most of the libraries have been recovered and restored on GitHub under a new organization named ngneat-archive. We will provide further updates as we learn more.
reddit.com/r/angular/comments/1txtp35/
Ng-News 26/15: Angular 22 was originally published in ng-news on Medium, where people are continuing the conversation by highlighting and responding to this story.
