看看这个简单的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方法查找。
但是,正如您可能猜到的那样,angular会在开发模式中抛出异常:
检查后表情发生了变化
之所以发生这种情况,是因为每个传递的_.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;
}
}
这样Angular很高兴,但我不会。
答案 0 :(得分:1)
您可以尝试使用'ChangeDetectorRef'类及其'detectChanges'方法。
也许这个问题可以帮到你:
答案 1 :(得分: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);
}
}
答案 2 :(得分: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()
getter函数。这可能会(CPU)昂贵。每当添加/删除/更改功能时,您可能最好(重新)生成服务中的已过滤列表。然后,StatusAreaComponent
只需在ngOnInit()
中获得对该已过滤数组的引用即可。这可能是我实现这一点的方式。
答案 3 :(得分:0)
存储过滤的数组和过滤条件,仅在过滤条件或数组项发生更改时重新创建过滤后的数组,并始终返回存储的数组。
另一种方法是将更改检测更改为onPush
,并通过注入ApplicationRef
并调用其.tick()