DEV Community

Cover image for Ng-News 25/28: Angular 20.1
ng-news for This is Angular

Posted on

Ng-News 25/28: Angular 20.1

Angular 20.1 was released, and it came with a set of nice new features. Here are the main ones:

🧠 Signals DevTools Integration

The Angular DevTools works on a component level. So you have to select the component first, activate the SignalGraph, and then you can see all the signals with context information.

Supported are signal(), computed(), linkedSignal(), and even effect().

This feature is still experimental. So we don't see the resource as one unit, but as a collection of multiple signals.

You also have the option to name your signals via the debugName property.

Example:

// Define a signal with a debug name for easier DevTools debugging const number = signal(1, { debugName: 'number', }); // Create a computed signal that doubles the `number` signal const double = computed(() => number() * 2, { debugName: 'doubleNumber', }); // Set up an effect to log the value of `double` whenever it changes effect(() => console.log(double()), { debugName: 'logger', }); 
Enter fullscreen mode Exit fullscreen mode

🌐 Extension for httpResource & HttpClient

The HttpClient — and logically also the httpResource, which uses the HttpClient under the hood — received a bit of a power-up.

It now allows us to pass through properties that the native fetch function exposes. These include support for timeouts, caching, redirect handling, and more.

Example:

// Define an httpResource with native fetch options passed through httpResource(() => ({ url: `/holiday/1/quiz`, priority: 'high', redirect: 'follow', cache: 'no-cache', credentials: 'same-origin', mode: 'no-cors', })); // Equivalent call using HttpClient directly with fetch-like options this.httpClient.get('/holiday/1/quiz', { priority: 'high', redirect: 'follow', cache: 'no-cache', credentials: 'same-origin', mode: 'no-cors', }); 
Enter fullscreen mode Exit fullscreen mode

🧪 Tests with Bindings

Whenever we wanted to test a component with property binding, we had to come up with a wrapper component to simulate a parent component, or execute ComponentRef.setInput().

Now, the TestBed.createComponent() method has a second parameter for bindings.

It doesn’t just support property binding but also event binding and two-way binding.


Given a component with two property bindings timeLeft and status:

export class QuizStatusComponent { timeLeft = input.required<number>(); status = input.required<{ correct: number; incorrect: number }>(); } 
Enter fullscreen mode Exit fullscreen mode

The "old way" was to rely on componentRef:

it('should show the time left', async () => { TestBed.configureTestingModule({ providers: [provideZonelessChangeDetection()], }).createComponent(QuizStatusComponent); // Setting the inputs fixture.componentRef.setInput('timeLeft', 10); fixture.componentRef.setInput('status', { correct: 0, incorrect: 0 }); const timeLeft = await screen.findByLabelText('Time remaining'); expect(timeLeft.textContent).toContain('Time Left: 10 seconds'); }); 
Enter fullscreen mode Exit fullscreen mode

In Angular 20.1, we can do that much more easily via createComponent:

it('should show the time left', async () => { TestBed.configureTestingModule({ providers: [provideZonelessChangeDetection()], }).createComponent(QuizStatusComponent, { bindings: [ inputBinding('timeLeft', () => 10), inputBinding('status', () => ({ correct: 0, incorrect: 0 })), ], }); const timeLeft = await screen.findByLabelText('Time remaining'); expect(timeLeft.textContent).toContain('Time Left: 10 seconds'); }); 
Enter fullscreen mode Exit fullscreen mode

🤖 MCP for Angular CLI

For AI-assisted development — which hopefully we’re all doing at this point — the Angular CLI provides an MCP server.

You need to register it in your IDE, and from that moment on, you can generate Angular code or ask Angular-specific questions right from your editor.

Depending on the IDE, in Cursor the registration for the MCP server would look like this:

mcp.json

{ "mcpServers": { "angular-cli": { "command": "npx", "args": ["@angular/cli", "mcp"] } } } 
Enter fullscreen mode Exit fullscreen mode

🧩 Miscellaneous

Sometimes we need to change or assign values to properties when a certain event happens. If it’s just a one-liner, we can now do that directly in the template — thanks to a syntax extension that supports different types of assignment operators.

Given that signals are the way forward and we should avoid logic in templates, this is likely an edge case.

Last but not least, it’s now possible to import image files in TypeScript, which can, for example, be encoded in base64 and reused in templates.

Before:

@Component({ template: ` <img alt="Eternal" src="assets/logo.png" /> ` }) export class Header {} 
Enter fullscreen mode Exit fullscreen mode

After:

import logo from '../../../assets/logo.png' with { loader: 'base64' }; @Component({ template: ` <img alt="Eternal" [src]="logo" /> `, }) export class Header { protected readonly logo = `data:image/png;base64,${logo}`; } 
Enter fullscreen mode Exit fullscreen mode

Yes, the older version is shorter — but the new version embeds the image directly into the component, so it doesn’t need to be loaded separately.

Top comments (0)