import { SU } from './../utils/string-util'; import { FilterUpdateBroadcastService } from './../providers/filter-update-broadcast.service'; import { Component, Input, OnInit, Output, EventEmitter, OnChanges, OnDestroy } from '@angular/core'; import { FilterInfo } from '../types/filter-info'; import { FiltersDataService } from '../providers/filters-data.service'; import { SelectedFiltersDataService } from '../providers/selected-filters-data.service'; import { Subscription } from 'rxjs/index'; import { FilterChangeNotifyService } from '../providers/filter-change-notify.service'; import { NameValue } from '../types/name-value'; import { FilterParentPipe } from '../pipes/filter.pipe'; /** * @author Harsha A.N.S */ @Component({ selector: 'ics-dropdown', templateUrl: './dropdown.component.html', styleUrls: ['./dropdown.component.scss'], providers: [FilterParentPipe] }) export class DropdownComponent implements OnInit, OnChanges, OnDestroy { @Input() filterInfo: FilterInfo; @Input() filterData: any[]; @Input() allFilterInstantiated: boolean; @Output() instantiated: EventEmitter; @Output() filterSet: EventEmitter; readonly ALL: string = 'All'; private parentSubscribe: Subscription; private childSubscribe: Subscription; private originalFilterData: any[]; // store the data will be used if filter is child private childCount: number; // to count how many childs have been updated selectedData: any; constructor(private filtersDataService: FiltersDataService, private fs: SelectedFiltersDataService, private filterBroadCast: FilterUpdateBroadcastService, private filterParent: FilterParentPipe, private broadcastService: FilterChangeNotifyService) { this.childSubscribe = this.filterBroadCast.notifyChild$.subscribe(item => this.isParent(item)); this.parentSubscribe = this.filterBroadCast.notifyParent$.subscribe(item => this.isChild(item)); this.instantiated = new EventEmitter(); this.filterSet = new EventEmitter(); } ngOnInit() { if (this.filterData) { // perform a deep clone operation this.originalFilterData = JSON.parse(JSON.stringify(this.filterData)); } else { throw Error(' filter data does not bounded for ' + this.filterInfo.name); } this.instantiated.emit(this.filterInfo); } ngOnChanges() { // if and only if all filter in current page are instaniated then only start assiging values // which is essential in first load of parent child dependency else parent cant notify the child // which isnt instantiated if (this.allFilterInstantiated) { this.init(); } } init() { // child should wait for the parent call in order to init for default values if (this.filterInfo.parents.length <= 0) { // is the data is in form of dependency data then transform the data accordingly if (this.filterData[0][this.filterInfo.name] !== undefined) { this.filterData = this.filterParent.transform(this.filterData, null, 'ALL', this.filterInfo.name); } this.updateFilterData(); this.setDefaultValue(); this.onOptionChange(); } } // check if data needs to be altered updateFilterData() { if (this.filterInfo.containsAll && SU.doesNotContainAll(this.filterData[0]) ) { // do not use un shift directly on data since it refers the main data. this.filterData = JSON.parse(JSON.stringify(this.filterData)); this.filterData.unshift(new NameValue(this.ALL, this.ALL)); } } doesNotContainAll(obj: NameValue): boolean { return obj.name.toUpperCase() === this.ALL.toUpperCase(); } setDefaultValue() { let index = 0; // if user hasnt specified default index then 0 if (this.filterInfo.defaultIndex && this.filterInfo.defaultIndex >= 0) { index = this.filterInfo.defaultIndex; } this.selectedData = this.filterData[index].value; } updateSelectedData(): Promise { return this.fs.storeSelectedData(this.filterInfo.name, this.selectedData); } notifyFilterChange() { this.broadcastService.notifyFilterChange(this.filterInfo); } onOptionChange() { this.updateSelectedData().then(res => { if (this.filterInfo.childs.length > 0) { // if this filter has childs notify them and only resolve once they notify back this.childCount = 0; this.filterBroadCast.notifyChild(this.filterInfo); } else { // resolve this filter directly this.resolve(); this.notifyFilterChange(); } }); } isParent(item: FilterInfo) { if (this.filterInfo.parents.length <= 0) { return; } // check if notifier is the parent of this filter const parent = this.filterInfo.parents.filter((pt) => pt === item.name); if (parent.length > 0) { // filter the child values according to all parent value // const parentData = this.fs.getSelectedData(item.name); const parents = this.filterInfo.parents; this.filterData = this.filterParent.transformMulti(this.originalFilterData, parents, this.fs.getSelectedDataList(parents), this.filterInfo.name); // now store the default value of child if (this.filterData[0].value !== 'All') { // case when filter contains All and this should be avoided this.updateFilterData(); } this.setDefaultValue(); this.onOptionChange(); // this filter is the child of notifier , hence resolve this by updating data and notify parent this.resolve(); this.filterBroadCast.notifyParent(this.filterInfo); } } isChild(item: FilterInfo) { if (this.filterInfo.childs.length <= 0) { return; } // check if notifier is the child of this filter const child = this.filterInfo.childs.filter(ch => ch === item.name); if (child.length > 0) { // this filters child is resolved and update the child count this.childCount = this.childCount + 1; // check if the all the childs has given the acknowledgment // if true then notify that this fitler is changed if (this.filterInfo.childs.length === this.childCount) { this.resolve(); this.notifyFilterChange(); } } } resolve() { this.filterSet.emit(this.filterInfo); } ngOnDestroy() { // unsubscribe to avoid memory leakage this.parentSubscribe.unsubscribe(); this.childSubscribe.unsubscribe(); } } export class FilterToDo { constructor(public name: string, public filterInfo: FilterInfo) { } }