-
Notifications
You must be signed in to change notification settings - Fork 26.9k
Description
Which @angular/* package(s) are the source of the bug?
core
Is this a regression?
No
Description
I'm not sure whether this is a bug or whether this is intended, but it feels unintuitive to me. Therefore "expected" below is what I would have expected.
Expected behaviour
Calling resouce.set(value) should always abort in-progress async loading
Actual behaviour
Calling resouce.reload() then calling resouce.set(value) before the async reload is complete, with the same value that was set for the resource before reload was called, does not abort the reload operation.
This creates an inconsistent behaviour. E.g.:
resource.set({});
resources.reload();
resource.set(undefined); // cancels the reload
resource.set(undefined);
resources.reload();
resource.set(undefined); // does not cancel the reloadExample reproduction
In the following component, click the "Load it" button to trigger the reload, then click the "Cancel it" button to set the resource explicitly to undefined before the async load operation has completed.
import {Component, resource, ResourceStatus} from '@angular/core';
import {JsonPipe} from '@angular/common';
@Component({
selector: 'app-root',
imports: [JsonPipe],
template: `
<p>
@if (something.value()) {
{{something.value() | json}}
} @else if (something.isLoading()) {
Loading...
} @else {
Load it?
}
</p>
@if (something.isLoading()) {
<p><button type="button" (click)="cancelIt()">Cancel it</button></p>
} @else {
<p><button type="button" (click)="loadIt()">Load it</button></p>
}
`
})
export class AppComponent {
readonly something = resource({
loader: async ({previous, abortSignal}) => {
if (previous.status === ResourceStatus.Idle) {
return undefined;
}
return await someLongRunningTask(abortSignal);
}
});
loadIt() {
this.something.reload();
}
cancelIt() {
// Setting a value after reload is called that is the same as the value
// which was set before reload was called does not cancel the reload action
this.something.set(undefined);
// whereas setting a different value to the previous one always aborts in-progress reload operations
// this.something.set({});
}
}
function someLongRunningTask(abortSignal: AbortSignal) {
return new Promise<unknown>((resolve, reject) => {
if (abortSignal.aborted) {
reject(abortSignal.reason);
return;
}
let timeout: number | undefined = undefined;
const abort = () => {
clearTimeout(timeout);
reject(abortSignal.reason);
};
abortSignal.addEventListener('abort', abort);
timeout = setTimeout(() => {
abortSignal.removeEventListener('abort', abort);
resolve({success: true});
}, 2_000)
})
}Please provide a link to a minimal reproduction of the bug
No response
Please provide the exception or error you saw
Please provide the environment you discovered this bug in (run ng version)
Angular CLI: 19.0.6
Node: 20.18.1
Package Manager: npm 10.8.2
OS: darwin arm64
Angular: 19.0.5
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1900.6
@angular-devkit/build-angular 19.0.6
@angular-devkit/core 19.0.6
@angular-devkit/schematics 19.0.6
@angular/cli 19.0.6
@schematics/angular 19.0.6
rxjs 7.8.1
typescript 5.6.3
zone.js 0.15.0
Anything else?
No response