import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core'; import { Field, Filter } from './filtering.interface'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { BehaviorSubject, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { FieldsService } from './fields.service'; import { FilteringService } from './filtering.service'; import { DEFAULT_FILTERING } from './filtering.constants'; @Component({ selector: 'app-filtering', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: FilteringComponent, multi: true }, FilteringService, FieldsService ], templateUrl: 'filtering.component.html', styleUrls: ['filtering.component.scss'], changeDetection: ChangeDetectionStrategy.Default }) export class FilteringComponent implements ControlValueAccessor, OnInit, OnDestroy, OnChanges { destroy$ = new Subject(); filtering$ = new BehaviorSubject([]); @Input() fields: Array; @Input() filtering: Array; @Input() addFilterButtonTitle: string; @Input() applyFilterButtonTitle: string; @Input() clearFilterButtonTitle: string; @Output() apply = new EventEmitter(); // ==== value ==== _value: Array = []; set value (value: any) { this._value = value || this._value; this.propagateChange(this._value); } get value () { return this._value; } // ==== value ==== // noinspection JSMethodCanBeStatic /** * Will be replaced when implementing registerOnChange * @param _ {TargetingSpec} */ propagateChange (_: Array) { return _; } // ==== implement ControlValueAccessor ==== writeValue (value: Array) { this._value = value || this._value; this.updateView(); } registerOnChange (fn: any) { this.propagateChange = fn; } registerOnTouched () { return; } // ==== implement ControlValueAccessor ==== updateView () { this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); } addFilter () { this.value.push({ field: this.fields[0].id, operator: Object.keys(this.fields[0].operator)[0] }); this.filteringService.set(this.value); } removeFilter (index) { this.value.splice(index, 1); this.filteringService.set(this.value); } onApply () { // Filter out filers without values const filtering = this.filteringService.get() .filter((filter) => Boolean(filter.value)); this.apply.emit(filtering); } clear () { const fields = this.fieldsService.get(); const statusField = fields.find((field) => field.id.indexOf('.effective_status') > -1); const defaultFilter = [].concat(DEFAULT_FILTERING)[0]; defaultFilter.field = statusField.id; this.filteringService.set([defaultFilter]); } ngOnChanges (changes) { if (changes.filtering) { this.filteringService.set(changes.filtering.currentValue); } if (changes.fields) { this.fieldsService.set(changes.fields.currentValue); } } ngOnDestroy () { this.destroy$.next(); } ngOnInit () { this.filteringService.filters .pipe( takeUntil(this.destroy$) ) .subscribe((filters: Filter[]) => { this.value = filters; }); this.fieldsService.set(this.fields); this.filteringService.set(this.filtering); } constructor (private changeDetectorRef: ChangeDetectorRef, private fieldsService: FieldsService, private filteringService: FilteringService) {} }