import { BehaviorSubject, merge, Observable, of as observableOf, Subject } from 'rxjs'; import { map, switchMap, takeUntil, take } from 'rxjs/operators'; import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { FormControlToken } from '../../../../shared/constants/form-control-token'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { TargetingSpec } from '../../interfaces/targeting-spec.interface'; import { SqueezedValueAccessor } from '../../../../shared/interfaces/squeeze-value-accessor.inteface'; import { LocalesApiService } from './locales-api/locales-api.service'; import { Locale } from './interfaces/locale.interface'; @Component({ selector: 'app-locales', templateUrl: 'locales.html', styleUrls: ['locales.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: LocalesComponent, multi: true }, {provide: FormControlToken, useExisting: LocalesComponent}, LocalesApiService ], changeDetection: ChangeDetectionStrategy.OnPush }) export class LocalesComponent implements ControlValueAccessor, SqueezedValueAccessor, OnInit, OnDestroy { _defaultSqueezedValue = '–'; destroy$ = new Subject(); squeezedValue$ = new BehaviorSubject(this._defaultSqueezedValue); inputValue$ = new Subject(); locales$: Observable>; select$ = new Subject(); remove$ = new Subject(); selected$ = new BehaviorSubject>([]); // ==== value ==== _value: TargetingSpec = {}; set value (value: any) { this._value = value || this._value; this.propagateChange(this._value); this.updateSqueezedValue(); } get value () { return this._value; } // ==== value ==== // noinspection JSMethodCanBeStatic /** * Will be replaced when implementing registerOnChange * @param _ {TargetingSpec} */ propagateChange (_: TargetingSpec) { return _; } // ==== implement ControlValueAccessor ==== writeValue (value: TargetingSpec) { this._value = value || this._value; this.updateSqueezedValue(); } registerOnChange (fn: any) { this.propagateChange = fn; } registerOnTouched () { return; } // ==== implement ControlValueAccessor ==== // ==== implement SqueezedValueAccessor ==== updateSqueezedValue () { this.squeezedValue$.next(this.selected$.getValue() .map((locale) => locale.name) .join('; ') || this._defaultSqueezedValue); } getSqueezedValue () { return this.squeezedValue$.getValue(); } focus () { return; } // ==== implement SqueezedValueAccessor ==== ngOnDestroy () { this.destroy$.next(); } ngOnInit () { this.locales$ = this.inputValue$ .pipe( takeUntil(this.destroy$), switchMap((inputValue) => { if (!inputValue) { return observableOf([]); } return this.localesApiService.locales$.pipe( take(1), map((locales: Array) => { return locales.filter((locale) => { return locale.name.toLowerCase() .includes(inputValue.toLowerCase()); }); }) ); }) ); merge( this.remove$ .pipe( takeUntil(this.destroy$), map((locale: Locale) => { return this.selected$.getValue() .filter((selectedLocale) => selectedLocale.key !== locale.key); }) ), this.select$ .pipe( takeUntil(this.destroy$), map((locale: Locale) => { return [locale].concat(this.selected$.getValue()); }) ) ) .subscribe((locales: Array) => { this.selected$.next(locales); this.value = Object.assign({}, { locales: locales.map((locale) => locale.key) }); }); } constructor (private localesApiService: LocalesApiService) {} }