2016-02-13 25 views
4

在這個簡單的Angular2部件請看:如何髒檢查Angular2中的可迭代組件屬性?

@Component({ 
    selector: 'status-area', 
    directives: [], 
    template: require('./status-area.tpl.jade') 
}) 

export class StatusAreaComponent { 

    constructor(private _settings: SettingsProvider) {} 

    get items() { 
    return _.filter(this._settings.features, (feature: any) => { 
     return feature.inStatusBar && feature.isEnabled; 
    }); 
    } 
} 

SettingsProvider有一個屬性特徵,這是由另一組件(例如SettingsPanel)改性。這些組件僅通過服務鏈接(無輸入參數)。

因此,正如您所看到的,我只需要從_settings.features屬性中只提取並標記爲狀態欄兼容功能。

爲此,我使用lodash方法查找。

然而,正如你可能已經猜到,角投在開發模式下的例外:它檢查

這是因爲_.filter()每次穿過返回數組的新實例後

表達發生了變化,但收集是一樣的。

我的問題是,你是如何解決這種情況的?或者可能有另一種解決方案/方法來處理這種情況。

在我看來,這將是如果angular2有特殊裝飾一樣,非常有用:

@checkIterable() 
get items() { 
    return _.filter(this._settings.features, (feature: any) => { 
     return feature.inStatusBar && feature.isEnabled; 
    }); 
    } 

我當然可以用另一種方法,事件和事件監聽器解決這個問題,但它產生了很多的樣板代碼。

看看這個例子:

export class StatusAreaComponent implements OnInit, OnDestroy { 

    protected _items; 
    protected _removeWatcherFn; 

    constructor(private settings: SettingsProvider) {} 

    ngOnInit() { 
    this._items = this._fetchItems(); 

    this._removeWatcherFn = this.settings.onChange.bind(() => { 
     this._items = this._fetchItems(); 
    }); 
    } 

    ngOnDestroy() { 
    this._removeWatcherFn(); 
    } 

    _fetchItems() { 
    return _.filter(this.settings.features, (feature: any) => { 
     return feature.inStatusBar; 
    }); 
    } 


    get items() { 
    return this._items; 
    } 
} 

這樣角是幸福的,但我不知道。

回答

1

既然你已經使用lodash您可以利用便捷的_.memoize方法來過濾緩存結果。它通常用於避免昂貴的計算,但在你的情況下,你可以從它的副作用中受益,因爲Angular不會有這個問題,過濾後的數組是每次檢查的不同對象。

以下是這個問題可能的解決方案:

@Component({ 
    selector: 'status-area', 
    directives: [], 
    template: require('./status-area.tpl.jade') 
}) 
export class StatusAreaComponent { 

    constructor(private _settings: SettingsProvider) { 
    this.initFilter(); 
    } 

    initFilter() { 

    function filterItems(items) { 
     return _.filter(items, (feature: any) => { 
     return feature.inStatusBar && feature.isEnabled; 
     }) 
    } 

    this.filterFeatures = _.memoize(filterItems, function(items) { 
     return filterItems(items).map(item => item.id).join(); 
    }); 
    } 

    get items() { 
    return this.filterFeatures(this._settings.features); 
    } 

} 

演示:http://plnkr.co/edit/MuYUO3neJdTs0DHluu0S?p=info

+0

好的解決方案!我試圖使用memoize,但我嘗試了錯誤的方式。我沒有提供緩存鍵功能。 –

0

只有當過濾條件或數組項目發生更改時,才存儲過濾的數組和過濾條件,並重新創建過濾數組,並始終返回存儲的數組。

另一種方法是改改檢測到onPush並通過注入ApplicationRef,並呼籲明確通知角約改變其.tick()

1

返回相同的陣列(參考)各一次。

export class StatusAreaComponent { 
    filteredItems = []; 
    constructor(private _settings: SettingsProvider) {} 
    get items() { 
    let filteredItems = this._settings.features.filter((feature: any) => { 
     return feature.inStatusBar && feature.isEnabled; 
    }); 
    this.filteredItems.length = 0; 
    this.filteredItems.push(...filteredItems); 
    return this.filteredItems; 
    } 
} 

注意...ES2015 feature

我假設你在你的模板中有類似*ngFor="#item of items">{{#item}}的東西。如果是這樣,你的items()吸氣功能將被調用每個變化檢測週期。這可能會導致(CPU)昂貴。無論何時添加/刪除/更改功能,您可能會更好(重新)在服務中生成過濾列表。然後您的StatusAreaComponent可以簡單地在ngOnInit()中獲得對該濾波陣列的引用。這可能是我如何實現這一點。

+0

該解決方案將打破更改檢測。因爲在每個檢測器中都會認爲這個特性沒有改變,組件視圖也不會被更新。 –

+0

@TimofeyYatsenko,我假設模板中有一個'NgFor'循環。如果是這樣,更改檢測將檢查數組中每個項目的綁定,因此即使數組(引用)未更改,視圖也會更新。這肯定有一些常見的困惑......請參閱[這個答案](http://stackoverflow.com/a/35106215/215945)瞭解更多信息。 –