import { Component, OnInit, Input, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; import { ViewConfig } from '../../models/view-config'; import { BaseComponent } from '../../../../base.component'; import { FormGroup, FormBuilder } from '@angular/forms'; import { ConfigRepositoryService } from '../../services/config-repository.service'; import { tap } from 'rxjs/operators'; import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher'; /** * List view for the categories. * * TODO: Creation of new Categories */ @Component({ selector: 'os-config-field', templateUrl: './config-field.component.html', styleUrls: ['./config-field.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class ConfigFieldComponent extends BaseComponent implements OnInit { public configItem: ViewConfig; /** * Option to show a green check-icon. */ public updateSuccessIcon = false; /** * The timeout for the success icon to hide. */ private updateSuccessIconTimeout: number | null = null; /** * The debounce timeout for inputs request delay. */ private debounceTimeout: number | null = null; /** * A possible error send by the server. */ public error: string | null = null; /** * The config item for this component. Just accept components with already populated constants-info. */ @Input() public set item(value: ViewConfig) { if (value.hasConstantsInfo) { this.configItem = value; if (this.form) { this.form.patchValue( { value: this.configItem.value }, { emitEvent: false } ); } } } /** * The form for this configItem. */ public form: FormGroup; /** * The matcher for custom (request) errors. */ public matcher = new ParentErrorStateMatcher(); /** * The usual component constructor * @param titleService * @param translate */ public constructor( protected titleService: Title, protected translate: TranslateService, private formBuilder: FormBuilder, private cdRef: ChangeDetectorRef, public repo: ConfigRepositoryService ) { super(titleService, translate); } /** * Sets up the form for this config field. */ public ngOnInit(): void { this.form = this.formBuilder.group({ value: [''] }); this.form.patchValue({ value: this.configItem.value }); this.form.valueChanges.subscribe(form => { this.onChange(form.value); }); } /** * Trigger an update of the data */ private onChange(value: any): void { if (this.debounceTimeout !== null) { clearTimeout(this.debounceTimeout); } this.debounceTimeout = setTimeout(() => { this.update(value); }, this.configItem.getDebouncingTimeout()); this.cdRef.detectChanges(); } /** * Updates the this config field. */ private update(value: any): void { // TODO: Fix the Datetimepicker parser and formatter. if (this.configItem.inputType === 'datetimepicker') { value = Date.parse(value); } this.debounceTimeout = null; this.repo .update({ value: value }, this.configItem) .pipe( tap( response => { this.error = null; this.showSuccessIcon(); }, error => { this.setError(error.error.detail); } ) ) .subscribe(); } /** * Show the green success icon on the component. The icon gets automatically cleared. */ private showSuccessIcon(): void { if (this.updateSuccessIconTimeout !== null) { clearTimeout(this.updateSuccessIconTimeout); } this.updateSuccessIconTimeout = setTimeout(() => { this.updateSuccessIcon = false; this.cdRef.detectChanges(); }, 2000); this.updateSuccessIcon = true; this.cdRef.detectChanges(); } /** * Sets the error on this field. */ private setError(error: string): void { this.error = error; this.form.setErrors({ error: true }); this.cdRef.detectChanges(); } /** * Uses the configItem to determine the kind of interation: * input, textarea, choice or date */ public formType(type: string): string { switch (type) { case 'integer': return 'number'; case 'colorpicker': return 'color'; default: return 'text'; } } }