2017-08-17 52 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