对于我的应用,ItemDetailComponent
是显示项目信息的位置。我有一个使用promise检索所有项目的服务。我使用ActivatedRoute
从网址路径中检索商品ID,然后运行服务,获取所有商品,然后找到上面检索到ID的商品,并将其分配给selectedItem
变量。
以下是item-detail.component.ts
:
export class ItemDetailComponent implements OnInit {
private title = 'Item Details'
private selectedItem: object
constructor(
private route: ActivatedRoute,
private itemService: ItemService
) {}
ngOnInit() {
const selectedItemId = this.route.snapshot.params.itemId
return this.itemService.getAllItems()
.then((items) => {
return _.find(items, item => item.itemId === selectedItemId)
})
.then((selectedItem) => {
this.selectedItem = selectedItem
console.log('Inside promise', this.selectedItem)
})
console.log('Outside promise', this.selectedItem)
}
}
这里是item-detail.component.html
模板,所以我可以显示我的项目,只是一个例子:
<div>
<h1>{{title}}</h1>
<div *ngIf="selectedItem">
<div><label>Item ID: </label>{{selectedItem.itemId}}</div>
</div>
</div>
不幸的是,应用程序只返回标题。然后我添加了两个console.log()
命令,发现在承诺完成之前呈现了promise和html模板之外的那个,并且当时没有selectedItem
可用。我怎样才能强制应用程序只有在解决了承诺后才能执行它们才能显示selectedItem
?
编辑:我在html模板中添加了一个新行,以便进一步检查:
<div>
<h1>{{title}}</h1>
<div><label>Item ID 1: </label>{{selectedItem.itemId}}</div>
<div *ngIf="selectedItem">
<div><label>Item ID 2: </label>{{selectedItem.itemId}}</div>
</div>
</div>
该应用显示“商品ID 1:”标签,但没有实际ID。控制台向我显示一条错误,指出“无法读取未定义的属性'itemId',再次确认整个模板在promise解决之前呈现,并且在加载数据后不会重新呈现。太奇怪了。
答案 0 :(得分:2)
您可以为获取所需数据的路线创建一个解析器。
https://angular.io/api/router/Resolve
https://blog.thoughtram.io/angular/2016/10/10/resolving-route-data-in-angular-2.html
答案 1 :(得分:0)
在类中添加一个布尔变量,如
private dataAvailable:boolean = false;
并且在订阅promise时,在数据可用时将其设为
then((selectedItem) => {
this.selectedItem = selectedItem;
this.dataAvailable=true;
console.log('Inside promise', this.selectedItem)
})
并在数据可用时在模板中呈现
<div>
<h1>{{title}}</h1>
<div *ngIf="dataAvailable">
<div><label>Item ID: </label>{{selectedItem.itemId}}</div>
</div>
</div>
它应该做的伎俩
答案 2 :(得分:0)
<强>更新强>
ngOnInit()
似乎只是一个事件处理程序钩子 - 返回任何不会影响它的东西。因此,我的旧答案将无效。
还有其他的解决方法,例如使用* ngIf或将它放在路由等中。但是我希望有一些像resolvePromise(): Promise
钩子这样会在渲染之前对分辨率施加条件。
这不是开发人员将样板放在每个组件中。
旧答案
最可能的原因是你在第二个then
中缺少return语句。
then((selectedItem) => {
this.selectedItem = selectedItem
console.log():
return selectedItem;//
}
答案 3 :(得分:0)
是否有可能ChangeDetection
在组件树的某个地方设置为OnPush
?
如果是这种情况,则模板不会自动重新呈现,因为没有任何内容会触发此组件的ChangeDetection
。
请注意设置为changeDetection: ChangeDetectionStrategy.OnPush
@Component({
selector: 'example',
template: `...`,
styles: [`...`],
changeDetection: ChangeDetectionStrategy.OnPush
})
此外,您已经使用Resolver
获得了有效的解决方案,您可以检查这是否有帮助:
export class ItemDetailComponent implements OnInit {
private title = 'Item Details'
private selectedItem: object
constructor(
private route: ActivatedRoute,
private itemService: ItemService,
// the reference to the components changeDetector is needed.
private changeDetectorRef: ChangeDetectorRef
) {}
ngOnInit() {
const selectedItemId = this.route.snapshot.params.itemId
return this.itemService.getAllItems()
.then((items) => {
return _.find(items, item => item.itemId === selectedItemId)
})
.then((selectedItem) => {
this.selectedItem = selectedItem
// this triggers the changedetection and the template should be rerendered;
this.changeDetectorRef.detectChanges();
console.log('Inside promise', this.selectedItem)
});
console.log('Outside promise', this.selectedItem)
}
}
这是一篇关于Angulars ChangeDetection的精彩文章:https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html