2017-09-28 122 views
0

後,我有角4應用與下面的構造服務:執行服務功能數組填充

constructor(private readonly http: Http) { 
    this.http.get(this.originUrl + 'api/ProductCategories/').subscribe(result => { 
     this.categories = result.json(); 
    }); 
} 

,並在這個服務的功能得到一個人的分類標識。

findCategory(fullSlug: string): number { 
    return this.categories.filter(c=>c.fullSlug == fullSlug)[0].id; 
} 

我需要在類別列表填充後從組件調用此函數。應用程序加載一次後,沒關係,因爲服務是從app.module加載的,但當我重新加載頁面(F5)時,我在findCategory函數中出現錯誤「無法讀取未定義的屬性」過濾器。

謝謝。

+0

顯示你怎麼用這個'findCategory'方法請告訴我,什麼是關係介乎這與某物構造這個用'findCategory'方法 –

+0

在組件我使用 構造函數(私人categoriesService:CategoriesService){} 到獲取實例並在ngAfterViewInit上使用 this.categoryId = this.categoriesService.findCategory(this.catStr); – dseferlis

回答

1

我因爲你的this.categories屬性被填充異步,你需要在你不從服務內部控制其他公共方法,使用時要考慮到這一點。

UPDATE: 由於這竟然是在這種情況下,該數據只是從數據源中檢索到的一次重要的,我建議要充分觀察到的從不是服務。意味着服務將始終返回可觀察的結果,並始終讓消費者處理訂閱。

只加載一次數據的技巧是使用share運算符。這將使得categories$可觀察到read more on the topic here)。簡而言之 - 它只會到達數據源一次,然後讓所有訂戶共享已經檢索的結果(請參閱下面的更新代碼)。

我建議將訂閱類別的責任委託給服務的使用者,然後將您想要進行過濾的數據作爲參數添加到 filter函數中。

這可以確保您在進行過濾時始終處理加載的數據。

在服務(YourService.ts現在):

originUrl = "...."; 
categories$: Observable<YourCategoryType[]>; 

constructor(private readonly http: Http) { 
    this.categories$ = this.http.get(this.originUrl + 'api/ProductCategories/') 
    .map(res => res.json()) 
    .share(); // <- Makes sure the call is only made ones, then re-uses the result 
} 

findCategory(fullSlug: string): Observable<number> { 
    return this.categories$ 
     .map(cats => cats.filter(cat => cat.fullSlug === fullSlug)[0].id); 
} 

而且在消費,例如一個組件:

categoryId: number; 

constructor(private yourService: YourService) {} 

someMethod(fullSlug: string) { 
    this.yourService 
    .findCategory(fullSlug) 
     .subscribe(catId => this.categoryId = catId); 
} 
+0

感謝您的回答。事情是我使用的類別:YourCategoryType [];在服務,所以我可以查詢數據庫只有第一次的應用程序加載。服務類別屬性用於填充另一個具有類別菜單的組件。然後在產品組件中,我需要查詢創建的類別對象以從fullSlug中獲取id。 – dseferlis

+0

@dseferlis查看我的更新回答 –

+0

謝謝Fredrik。我不確定這是否正確。也許我錯過了一些東西。您建議this.categories $ .filter。但類別$是Observable 。 ProductCategory []中沒有fullSlug,但是在ProductCategory中。此作品: – dseferlis

0

這真是不可預測的,你沒有辦法控制HTTP - 當它在Service中的構造函數中時 - 請求。

我建議你有一個「幫手」的方法,以便你可以控制流量。在這種幫助方法中,我們可以檢查categories$是否爲undefined。如果是,請進行http-call。然後,只需使用該方法在服務和執行你的魔法;)因此,像這樣在您的服務:

categories$: Observable<ProductCategory[]> 

getCategories() { 
    if(this.categories$ === undefined) { 
    this.categories$ = this.http.get(this.originUrl + 'api/ProductCategories/') 
     .map(res => res.json()) 
    } 
    return this.categories$ 
} 

然後,如前所述,在其他服務方法,只需調用上面的一個......所以,如調用從組件findCategory時,這將是您的服務的情況:

findCategory(fullSlug: string): number { 
    return this.getCategories() 
    .map(data => data.filter(c => c.fullSlug == fullSlug)[0].id) 
} 

..to其結果,那麼您可以訂閱的組件。

+0

如果它在構造函數中沒關係。構造函數不會被多次調用。我認爲這是.map,告訴應用程序隨時需要執行獲取的類別$。我用相同的結果嘗試了你的建議。不管怎樣,謝謝你。 – dseferlis

+0

是的,它只被調用一次,但你會得到這種錯誤,因爲你無法控制它,因此當你刷新'類別$'時,它是未定義的。用上面的代碼,錯誤不會發生。上面的代碼應該可以正常工作,您是否可以在重新編譯或重新編譯時重現問題? – Alex

+0

與Fredrik的回答一樣,問題在於,即使類別$未定義,http.get也會每次運行。請查看以下網址:https://i.imgur.com/yViN4du.png https://i.imgur.com/gVHvOlL.png 您可以看到類別$僅在第一次詢問類別時才被定義(id: 357)。在下一次調用(ID:30)被定義爲「Categories is undefined」不顯示,但在服務器上我碰到: 執行操作方法Kappakosgr.Web.Controllers.ProductsController.Get(Kappakosgr.Web)帶參數(null)) - ModelState是有效的。 我會嘗試把這個放在笨蛋,但不容易包括api。 – dseferlis