Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 如何在Angular2中脏检iterable组件属性?_Typescript_Angular - Fatal编程技术网

Typescript 如何在Angular2中脏检iterable组件属性?

Typescript 如何在Angular2中脏检iterable组件属性?,typescript,angular,Typescript,Angular,看看这个简单的Angular2组件: @Component({ selector: 'status-area', directives: [], template: require('./status-area.tpl.jade') }) export class StatusAreaComponent { constructor(private _settings: SettingsProvider) {} get items() { return _.fi

看看这个简单的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有一个属性features,该属性由另一个组件(例如SettingsPanel)修改。此组件仅由服务链接(无输入参数)

因此,正如您所看到的,我只需要从_settings.features属性中获取已启用并标记为状态栏兼容的功能

为此,我使用lodash方法查找

然而,正如您可能猜到的,angular在开发模式中抛出了一个异常:

表达式在选中后已更改

之所以发生这种情况,是因为每次传递都会返回数组的新实例,但集合是相同的

我的问题是,你如何解决这种情况?或者可能有另一种解决方案/方法来处理这种情况

在我看来,如果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很高兴,但我不高兴。

存储过滤的数组和过滤条件,仅当过滤条件或数组项更改时重新创建过滤的数组,并始终返回存储的数组


另一种方法是将更改检测更改为
onPush
,并通过注入
ApplicationRef
并调用其
.tick()

,显式通知Angular有关更改的信息。您可以尝试使用'ChangeDetectorRef'类及其'detectChanges'方法

也许这个问题可以帮助你:


因为您已经在使用lodash,所以可以使用方便的方法来缓存过滤结果。它通常用于避免昂贵的计算,但在您的情况下,您可以从它的副作用中受益,因为对于每个检查,过滤数组都是不同的对象,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);
  }

}
演示:每次返回相同的数组(参考)

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;
  }
}
请注意,
是一个


我假设您的模板中有类似于
*ngFor=“#item of items”>{{{#item}}}
的内容。如果是这样,将为每个更改检测周期调用
items()
getter函数。这可能会使CPU变得昂贵。无论何时添加/删除/更改功能,您最好在服务中(重新)生成筛选列表。然后,您的
StatusAreaComponent
只需在
ngOnInit()
中获取一次对该过滤数组的引用即可。这可能就是我实现此功能的方式。

此解决方案将破坏更改检测。因为在每个检查中,检测器都会认为此属性没有更改,组件视图也不会更新。@TimofeyYatsenko,我假设模板中有一个
NgFor
循环。如果是这样,更改检测将检查数组中每个项的绑定,因此视图将被更新,即使数组(引用)没有更改。关于这一点肯定有一些常见的困惑。。。有关更多信息,请参阅。好的解决方案!我试过使用memoize,但我用了错误的方式。我没有提供缓存键功能。