2017-08-17 53 views
5

对于我的应用程序,ItemDetailComponent是显示项目的信息。我有一个使用诺言检索所有项目的服务。我使用ActivatedRoute从URL路径检索项目ID,然后运行服务,获取所有项目,然后找到具有上面检索的ID的项目,并将其分配给selectedItem变量。如何在组件中的承诺解决后让Angular 2呈现HTML模板?

这里是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()命令,发现承诺之外的一个以及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解析之前呈现,并且在数据加载后不会重新呈现。太奇怪了。

+1

*“我该如何强制应用程序执行它们,只有在解决承诺后才能执行它们是否显示了selectedItem?“*。你不需要。模板将自动重新渲染。真正的问题是你得到“内部承诺”日志和'selectedItem'得到妥善解决? – dfsq

+0

是的,里面的承诺日志显示我很好的项目,我想显示的细节。 – Duc

+1

是标题属性绑定好吗?你可以发布一个plunkr请致电 – Tsar

回答

0

在您的班级中添加一个布尔变量,如

private dataAvailable:boolean = false;

,并在订阅的承诺,当数据可用

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> 

它应该做的伎俩

+0

我刚刚尝试过,实际上并没有帮助。我也认为这是行不通的,因为'selectedItem'和'dataAvailable'在同一个承诺中被赋予了新的值,所以它们没有任何区别。根据dfsq指出的 – Duc

+0

,一旦数据可用,模板应该重新渲染。!你能为同样的东西创建一个plunk吗? –

+0

由于item服务从连接到dev中的远程服务器的docker容器中检索信息,因此很多工作都是为此创建一个plunker。 – Duc

0

更新

ngOnInit()似乎只是一个事件处理程序挂钩 - 返回任何东西都不会影响任何东西看起来。因此,我的旧回答将不起作用。

还有其他的解决方法,如使用* ngIf或将其放入路由等,但我希望有像resolvePromise(): Promise挂钩,可以在渲染前解决条件。

这不是开发人员将样板放在每个组件中。

老答案

最有可能是因为你缺少return语句在第二then

then((selectedItem) => { this.selectedItem = selectedItem console.log(): return selectedItem;// }

+0

刚试过,太糟糕了,不是:( – Duc

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) 
    } 
} 

这里是一个伟大的文章About Angulars ChangeDetection:https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html