How to check dirty property of iterable component in Angular2?

Take a look at this simple Angular2 component:

@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 has propertywhich is modified by another component (e.g. SettingsPanel). These components are connected only by the service (without input parameters).

So, as you saw, I only need to activate and mark as status-compatible functions from the _settings.features property.

For this, I use the lodash search method.

However, as you might have guessed, angular throws an exception in design mode:

Expression changed after checking it.

This is because _.filter()for each pass it returns a new instance of the array, but the collection is the same.

, ? / .

-, , 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 , .

+4
4

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

+1

'ChangeDetectorRef' 'detectChanges'.

, :

+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.

, - *ngFor="#item of items">{{#item}} . , items() getter . (CPU). , (re) // . StatusAreaComponent ngOnInit(). , .

+1

Store the filtered array and filter criteria and recreate the filtered array only when the filter criteria or array elements are changed and always return the stored array.

Another way is to change the change detection to onPushand explicitly declare the changes to Angular by entering ApplicationRefand calling it.tick()

0
source

Source: https://habr.com/ru/post/1628616/


All Articles