Angular: 我怎样才能像往常一样从几个可观察数组中收集数据?
Angular: How can I collect data from a few observable as usual array?
我需要做下一个 - 从后端获取数据并将其转发到 child 组件:
...
@Component({
selector: 'my-component',
template: `<my-child-component [data]="data"></my-child-component>`
})
public data = [];
ngOnInit() {
this.service.getParentData().subscribe(res => {
res.map(r => this.service.getChildDatas(r.id)
.subscribe(child => this.data.push(child)));
});
}
但是在 child 组件中,当我尝试在 ngOnChanges 中打印数据时,我只看到奇怪的数组,我可以看到元素,但长度等于 0:
它是如何工作的以及如何实现我的 objective(将数据传递给 child 并像处理数组一样处理数据)?
您似乎有 2 个要通过管道传输的可观察对象,一个接一个。
您需要使用 rxJS operators 来实现。
实现它的方法是使用运算符 switchMap 或 mergeMap,具体取决于您是否希望将第一个更改为 re-trigger 第二个。
然后使用 forkJoin 运算符,以列表形式订阅可观察和威胁结果列表
假设您首先收到一个数组,并且需要每个数组值通过您将拥有的另一个服务获取子项
ngOnInit() {
this.service.getParentData()
.pipe(switchMap((parentData: {id: string}[]) => {
return forkJoin(parentData.map(r =>
this.service.getChildDatas(r.id))
})
.subscribe((childData: any[]) => {this.data = childData});
}
ngOnChange
- 当指令的任何 data-bound 属性 更改时调用的生命周期挂钩。
在这里你绑定了一个数组,它被视为 object.That 意味着当你发送新对象时 ngOnChange
将被触发,在我们的例子中是一个新数组(意味着新引用id).
Angular 使用相等检查运算符 === 来检测指令的输入何时更改。
=== 运算符检查它正在检查的对象中的引用更改。
在这里您更改的是对象的内容,而不是对象引用。
ngOnChange
将被触发,对于任何类型的对象,当有引用更改时意味着新对象。
所以第一个解决方案是
ngOnInit(){
this.service.getParentData().subscribe(res => {
res.map(r => this.service.getChildDatas(r.id)
.subscribe(child => {
this.data.push(child);
this.data = [...this.data]; // It will re assign new instance
data(Array) on every push
}));
});
}
但我会建议您在这里稍微优化一下代码,例如
ngOnInit(){
this.service.getParentData().pipe(
concatMap((res) => this.service.getChildDatas(res.id))
).subscribe({
next: (res) => {
this.data.push(res);
this.data = [...this.data];
},
});
}
第二个解决方案
通过将自定义对象与 angular trackBy
绑定。 angular 将通过 trackBy
索引而不是对象引用来比较对象的相等性,这也会提高性能。
<my-child-component [data]="{trackBy:data.length,data:data}"></my-child-component>
ngOnChanges(changes: SimpleChanges): void {
console.log(changes.data.currentValue.data);
}
更新:
您使用了 .push
,所以我假设您正在接收单个数据,但是如果您正在接收一个数组,那么您可以将 res 数组分配给 this.data
,通过这样做,您每次都在更改引用
ngOnInit(){
this.service.getParentData().pipe(
concatMap((res) => this.service.getChildDatas(res.id))
).subscribe({
next: (res) => {
this.data = res;
},
});
}
再来一个Update
当您可能要处理同时更改的多个属性,或者希望对多个属性执行某些操作时,请使用 ngOnChanges
。
但是如果你想处理特定的 属性 变化,那么更好的选择是使用 setter 和 @Input
。
@Input() set data(data:any[]){
console.log(data);
};
我觉得这个博客很有帮助Detecting @Input changes in Angular with ngOnChanges and Setters
我需要做下一个 - 从后端获取数据并将其转发到 child 组件:
...
@Component({
selector: 'my-component',
template: `<my-child-component [data]="data"></my-child-component>`
})
public data = [];
ngOnInit() {
this.service.getParentData().subscribe(res => {
res.map(r => this.service.getChildDatas(r.id)
.subscribe(child => this.data.push(child)));
});
}
但是在 child 组件中,当我尝试在 ngOnChanges 中打印数据时,我只看到奇怪的数组,我可以看到元素,但长度等于 0:
您似乎有 2 个要通过管道传输的可观察对象,一个接一个。 您需要使用 rxJS operators 来实现。
实现它的方法是使用运算符 switchMap 或 mergeMap,具体取决于您是否希望将第一个更改为 re-trigger 第二个。
然后使用 forkJoin 运算符,以列表形式订阅可观察和威胁结果列表
假设您首先收到一个数组,并且需要每个数组值通过您将拥有的另一个服务获取子项
ngOnInit() {
this.service.getParentData()
.pipe(switchMap((parentData: {id: string}[]) => {
return forkJoin(parentData.map(r =>
this.service.getChildDatas(r.id))
})
.subscribe((childData: any[]) => {this.data = childData});
}
ngOnChange
- 当指令的任何 data-bound 属性 更改时调用的生命周期挂钩。
在这里你绑定了一个数组,它被视为 object.That 意味着当你发送新对象时 ngOnChange
将被触发,在我们的例子中是一个新数组(意味着新引用id).
Angular 使用相等检查运算符 === 来检测指令的输入何时更改。 === 运算符检查它正在检查的对象中的引用更改。
在这里您更改的是对象的内容,而不是对象引用。
ngOnChange
将被触发,对于任何类型的对象,当有引用更改时意味着新对象。
所以第一个解决方案是
ngOnInit(){
this.service.getParentData().subscribe(res => {
res.map(r => this.service.getChildDatas(r.id)
.subscribe(child => {
this.data.push(child);
this.data = [...this.data]; // It will re assign new instance
data(Array) on every push
}));
});
}
但我会建议您在这里稍微优化一下代码,例如
ngOnInit(){
this.service.getParentData().pipe(
concatMap((res) => this.service.getChildDatas(res.id))
).subscribe({
next: (res) => {
this.data.push(res);
this.data = [...this.data];
},
});
}
第二个解决方案
通过将自定义对象与 angular trackBy
绑定。 angular 将通过 trackBy
索引而不是对象引用来比较对象的相等性,这也会提高性能。
<my-child-component [data]="{trackBy:data.length,data:data}"></my-child-component>
ngOnChanges(changes: SimpleChanges): void {
console.log(changes.data.currentValue.data);
}
更新:
您使用了 .push
,所以我假设您正在接收单个数据,但是如果您正在接收一个数组,那么您可以将 res 数组分配给 this.data
,通过这样做,您每次都在更改引用
ngOnInit(){
this.service.getParentData().pipe(
concatMap((res) => this.service.getChildDatas(res.id))
).subscribe({
next: (res) => {
this.data = res;
},
});
}
再来一个Update
当您可能要处理同时更改的多个属性,或者希望对多个属性执行某些操作时,请使用 ngOnChanges
。
但是如果你想处理特定的 属性 变化,那么更好的选择是使用 setter 和 @Input
。
@Input() set data(data:any[]){
console.log(data);
};
我觉得这个博客很有帮助Detecting @Input changes in Angular with ngOnChanges and Setters