如何在解析组件中的promise后使Angular 2呈现HTML模板?

时间:2017-08-17 09:44:32

标签: html angular typescript

对于我的应用,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解决之前呈现,并且在加载数据后不会重新呈现。太奇怪了。

4 个答案:

答案 0 :(得分:2)

答案 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