我正在尝试使我的代码尽可能具有反应性,从显式路由订阅切换到
withcomponentinputbinding
。
export class CustomerProfileComponent {
private readonly oms = inject(OMSService);
private readonly route = inject(ActivatedRoute);
id = input<number>();
// this works but isn't using the mapped input signal
customer = toSignal(
this.route.params.pipe(
switchMap((params) => this.oms.getCustomer(Number(params['id'])))
)
);
// this doesn't work because getCustomer returns an Observable.
// Adding toSignal() doesn't work either, due to the context, but
// looking for something like this!
xcustomer = computed(() => this.oms.getCustomer(this.id()));
}
如果我使用路线
http://localhost:4200/#/customers/12
进行调用,它会将 {{ id() }}
的输出显示为 12,如映射路线所述,所以我知道这是有效的。但 xcustomer
计算值未得到解析,输出为:
{ "source": { "source": { "source": {} } } }
服务调用签名是:
getCustomer(id?: number): Observable<Customer>
有没有办法以这种方式使用从路由绑定的InputSignal作为计算源? 使用 Angular 18.2.11.
您正在使用
computed
它返回一个可观察值,但我猜您想在没有可观察值的情况下访问内部数据。那么 effect
是正确的选择,因为它可以访问内部可观察对象内的数据并更新属性或信号。更新 effect
内的信号将引发错误:
NG0600:默认情况下,不允许在
或computed
中写入信号。使用effect
中的allowSignalWrites
启用此内部效果。CreateEffectOptions
为了克服这个问题,我们可以使用
untracked
,它不跟踪信号更新并消除错误。
@Component({
selector: 'app-child',
standalone: true,
imports: [CommonModule],
template: `
{{id()}}<br/><br/>
{{xcustomer | json}}<br/><br/>
{{xcustomerSignal() | json}}
`,
})
export class Child {
private readonly oms = inject(OMSService);
id = input<number>();
xcustomer: any;
xcustomerSignal = signal({});
constructor() {
effect(() => {
this.oms.getCustomer(this.id()).subscribe((xcustomer: any) => {
this.xcustomer = xcustomer; // using property
// untracked(() => {
this.xcustomerSignal.set(xcustomer);
// });
});
});
}
}
import {
Component,
input,
computed,
inject,
Injectable,
effect,
signal,
untracked,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
RouterModule,
provideRouter,
withComponentInputBinding,
} from '@angular/router';
import { of, firstValueFrom } from 'rxjs';
import { CommonModule } from '@angular/common';
@Injectable({
providedIn: 'root',
})
export class OMSService {
getCustomer(id: number | undefined) {
return of({
id,
data: Math.random(),
});
}
}
@Component({
selector: 'app-child',
standalone: true,
imports: [CommonModule],
template: `
{{id()}}<br/><br/>
{{xcustomer | json}}<br/><br/>
{{xcustomerSignal() | json}}
`,
})
export class Child {
private readonly oms = inject(OMSService);
id = input<number>();
xcustomer: any;
xcustomerSignal = signal({});
constructor() {
effect(() => {
this.oms.getCustomer(this.id()).subscribe((xcustomer: any) => {
this.xcustomer = xcustomer; // using property
// untracked(() => {
this.xcustomerSignal.set(xcustomer);
// });
});
});
}
}
@Component({
selector: 'app-root',
standalone: true,
imports: [Child, RouterModule],
template: `
<a routerLink="/child/1">1</a> |
<a routerLink="/child/2">2</a><br/><br/><br/>
<router-outlet/>
`,
})
export class App {
name = 'Angular';
}
bootstrapApplication(App, {
providers: [
provideRouter(
[
{
path: 'child/:id',
component: Child,
},
],
withComponentInputBinding()
),
],
});