import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { targetingSpecInitial } from '../interfaces/targeting-spec.interface'; import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; import { targetingFormInitial } from './targeting-form.reducer'; import { Store } from '@ngrx/store'; import { AppState } from '../../../../app/reducers/index'; import { TargetingService } from '../targeting.service'; import { Subject } from 'rxjs'; import { distinctUntilChanged, filter, map, merge, skip, take, takeUntil } from 'rxjs/operators'; import { getSpecFromFormValue } from '../targeting.constants'; import { TargetingFormService } from './targeting-form.service'; import { TargetingAudiencesService } from '../targeting-audiences/targeting-audiences.service'; import { AudienceState } from '../audience/audience.interface'; import { AudienceService } from '../audience/audience.service'; import isEqual from 'lodash-es/isEqual'; @Component({ selector: 'app-targeting-form', templateUrl: 'targeting-form.html', styleUrls: ['targeting-form.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class TargetingFormComponent implements OnInit, OnDestroy { destroy$ = new Subject(); targeting$; audienceEditIndex$; formValue$; audienceEdited$; @Output() changeForm = new EventEmitter(); editMode = false; _formLegendDefault = 'FORM FOR MULTIPLE AUDIENCE CREATION'; _submitTextDefault = 'CREATE'; formLegend = this._formLegendDefault; submitText = this._submitTextDefault; // TODO: accountId should be set from AppState adaccountId = 'act_944874195534529'; targetingForm: FormGroup = this.setForm(); /** * Set model driven form using passed form value or initial form value * @param formValue */ setForm (formValue = {}) { const groupData = {}; formValue = Object.assign({}, targetingFormInitial, formValue); for (const name in formValue) { if (formValue.hasOwnProperty(name)) { groupData[name] = this.formBuilder.array( formValue[name].map((data) => this.formBuilder.control(data)) ); } } return this.formBuilder.group(groupData); } updateForm (formValue) { if (isEqual(formValue, this.targetingForm.value)) { return; } this.targetingForm = this.setForm(formValue); this.changeDetectorRef.markForCheck(); } /** * When submitted */ onSubmit () { if (this.editMode) { /** * Update audience */ this.audienceEdited$ .pipe( take(1) ) .subscribe(({index, audience}) => { const formValue = this.targetingForm.value; const spec = getSpecFromFormValue(formValue); const audienceEdited = Object.assign({}, audience, {formValue, spec}); this.targetingAudiencesService.extendAudience(audienceEdited) .subscribe((extendedAudience) => { this.targetingAudiencesService.updateAudience(index, extendedAudience); }); }); /** * Restore splitting form */ this.formValue$ .pipe( take(1) ) .subscribe((formValue) => { this.updateForm(formValue); this.audienceService.setEditAudienceIndex(null); }); } else { this.changeForm.emit(this.targetingForm.value); } } /** * Add another control by name */ addControl (name: string) { const control = this.targetingForm.controls[name]; control.push(this.formBuilder.control(targetingSpecInitial)); } /** * Remove control by name and index * @param name * @param i */ removeControl (obj: { name: string, i: number }) { const control = this.targetingForm.controls[obj.name]; control.removeAt(obj.i); } processAudienceEditIndex (index, audience?: AudienceState) { const editMode = audience && index !== null; this.editMode = editMode; this.submitText = editMode ? 'SAVE' : this._submitTextDefault; this.formLegend = editMode ? `EDIT AUDIENCE: "${audience.name}"` : this._formLegendDefault; this.changeDetectorRef.markForCheck(); } ngOnDestroy () { this.destroy$.next(); } ngOnInit () { this.targeting$ = this._store.pipe(TargetingService.getModel); this.audienceEditIndex$ = this.targeting$.pipe( takeUntil(this.destroy$), skip(2), map(({audienceIndexes}) => audienceIndexes.editIndex), distinctUntilChanged() ); this.audienceEdited$ = this.targeting$ .pipe( takeUntil(this.destroy$), filter(({audienceIndexes}) => audienceIndexes.editIndex !== null), map(({audienceIndexes, audiences}) => { return { index: audienceIndexes.editIndex, audience: audiences[audienceIndexes.editIndex] }; }) ); this.formValue$ = this._store.pipe( TargetingFormService.getModel, takeUntil(this.destroy$) ); this.audienceEditIndex$ .subscribe((index) => this.processAudienceEditIndex(index)); this.audienceEdited$ .subscribe(({index, audience}) => this.processAudienceEditIndex(index, audience)); /** * Update form for new formValue */ this.audienceEdited$ .pipe( map(({audience}) => audience.formValue), merge(this.formValue$) ) .subscribe((formValue) => this.updateForm(formValue)); } constructor (private _store: Store, private changeDetectorRef: ChangeDetectorRef, private targetingAudiencesService: TargetingAudiencesService, private audienceService: AudienceService, private formBuilder: FormBuilder) {} }