From 27d05e667a9f4fd7cba260b219f27f3e81fec576 Mon Sep 17 00:00:00 2001 From: Andria Capai Date: Wed, 19 Apr 2023 17:36:43 +0200 Subject: [PATCH] feat: prevent form appear if no type-site - Hide form if btn-list type-site not selected - Add custom error message mat-error if not selected (directive + custom message) WIP: error message is showing up only if not selected after touched . Maybe need to use asyncValidator ? Reviewed-by: andriac [Refs_tickets]: #5 , #6 , #54 --- .../btn-select/btn-select.component.html | 3 +- .../btn-select/btn-select.component.ts | 13 ++++++- .../monitoring-form.component-g.html | 2 +- .../monitoring-form.component-g.ts | 37 ++++++++++++++++--- .../monitoring-sites-create.component.html | 1 + .../monitoring-visits.component.html | 1 + .../monitoring-visits.component.ts | 4 +- frontend/app/gnModule.module.ts | 3 +- frontend/app/interfaces/object.ts | 3 ++ frontend/app/services/form.service.ts | 14 ++++++- .../app/utils/matErrorMessages.directive.ts | 37 +++++++++++++++++++ 11 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 frontend/app/utils/matErrorMessages.directive.ts diff --git a/frontend/app/components/btn-select/btn-select.component.html b/frontend/app/components/btn-select/btn-select.component.html index c852dfbd1..3a47c7e6a 100644 --- a/frontend/app/components/btn-select/btn-select.component.html +++ b/frontend/app/components/btn-select/btn-select.component.html @@ -1,6 +1,6 @@ {{ titleBtn }} - + + diff --git a/frontend/app/components/btn-select/btn-select.component.ts b/frontend/app/components/btn-select/btn-select.component.ts index 195ab17fe..e6df25e6a 100644 --- a/frontend/app/components/btn-select/btn-select.component.ts +++ b/frontend/app/components/btn-select/btn-select.component.ts @@ -8,12 +8,13 @@ import { Output, ViewChild, } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { FormControl, Validators } from '@angular/forms'; import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { Observable, iif, of } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'; import { JsonData } from '../../types/jsondata'; +import { FormService } from '../../services/form.service'; export interface EmptyObject { name: string; @@ -30,6 +31,7 @@ export class BtnSelectComponent implements OnInit { isInit = false; separatorKeysCodes: number[] = [ENTER, COMMA]; myControl = new FormControl(); + listOpNeeded = new FormControl([],[Validators.required, Validators.minLength(1)]) @Input() placeholderText: string = 'Selectionnez vos options dans la liste'; @Input() titleBtn: string = 'Choix des options'; @@ -52,9 +54,10 @@ export class BtnSelectComponent implements OnInit { @Output() public sendobject = new EventEmitter(); - constructor() {} + constructor(private _formService: FormService) { } ngOnInit() { + if(this.isInitialValues && !this.isInit){ this.initFromExistingObj(this.paramToFilt) this.objToEdit.map(val => this.addObject(val)) @@ -73,6 +76,8 @@ export class BtnSelectComponent implements OnInit { }), map((res) => (res.length > 0 ? res : [{ name: 'Pas de résultats' }])) ); + this.listOpNeeded.setValue(this.listOptionChosen) + this._formService.changeExtraFormControl(this.listOpNeeded,"listOptBtnSelect") } remove(option: string): void { @@ -86,6 +91,8 @@ export class BtnSelectComponent implements OnInit { delete this.configObjAdded[option]; } this.sendobject.emit(this.configObjAdded); + this.listOpNeeded.setValue(this.listOptionChosen) + this._formService.changeExtraFormControl(this.listOpNeeded,"listOptBtnSelect") } selected(event: MatAutocompleteSelectedEvent): void { @@ -95,6 +102,8 @@ export class BtnSelectComponent implements OnInit { : null; this.optionInput.nativeElement.value = ''; this.myControl.setValue(null); + this.listOpNeeded.setValue(this.listOptionChosen) + this._formService.changeExtraFormControl(this.listOpNeeded,"listOptBtnSelect") } filterOnRequest(val: string, keyToFilt: string): Observable { diff --git a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html index 7f4f5f46e..27b66a108 100644 --- a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html +++ b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.html @@ -18,7 +18,7 @@

Attention

-
+
diff --git a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts index 6ef0d1724..29a8578e9 100644 --- a/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts +++ b/frontend/app/components/monitoring-form-g/monitoring-form.component-g.ts @@ -11,7 +11,7 @@ import { IDataForm } from '../../interfaces/form'; import { ApiGeomService } from '../../services/api-geom.service'; import { ConfigJsonService } from '../../services/config-json.service'; import { FormService } from '../../services/form.service'; -import { ObjectService } from '../../services/object.service'; +import { IExtraForm } from '../../interfaces/object'; @Component({ selector: 'pnx-monitoring-form-g', @@ -34,6 +34,10 @@ export class MonitoringFormComponentG implements OnInit { @Input() sites: {}; @Input() apiService: ApiGeomService; + @Input() isExtraForm:boolean = false; + + extraForm: IExtraForm; + hideForm: boolean = false; dataForm: IDataForm; searchSite = ''; @@ -68,11 +72,16 @@ export class MonitoringFormComponentG implements OnInit { tap((data) => { this.obj = data; this.obj.bIsInitialized = true; - this.apiService.init(this.obj.endPoint, this.obj.objSelected); + this.obj.id = this.obj[this.obj.pk] }), - mergeMap((data: any) => this._configService.init(data.moduleCode)) + mergeMap((data: any) => this._configService.init(data.moduleCode)), + mergeMap(() => this._formService.currentExtraFormCtrl ) ) - .subscribe(() => { + .subscribe((frmCtrl) => { + + this.isExtraForm ? this.addExtraFormCtrl(frmCtrl) : null; + this.isExtraForm ? this.checkValidExtraFormCtrl() : null; + this.queryParams = this._route.snapshot.queryParams || {}; this.bChainInput = this._configService.frontendParams()['bChainInput']; @@ -293,7 +302,6 @@ export class MonitoringFormComponentG implements OnInit { onSubmit() { const { patch_update, ...sendValue } = this.dataForm; const objToUpdateOrCreate = this._formService.postData(sendValue, this.obj); - console.log(objToUpdateOrCreate); const action = this.obj.id ? this.apiService.patch(this.obj.id, objToUpdateOrCreate) : this.apiService.create(objToUpdateOrCreate); @@ -381,6 +389,25 @@ export class MonitoringFormComponentG implements OnInit { this.procesPatchUpdateForm(); } + addExtraFormCtrl(frmCtrl: IExtraForm){ + if (frmCtrl.frmName in this.objForm.controls){ + this.objForm.setControl(frmCtrl.frmName,frmCtrl.frmCtrl) + } else{ + this.objForm.addControl(frmCtrl.frmName,frmCtrl.frmCtrl) + } + + this.extraForm = frmCtrl + } + + checkValidExtraFormCtrl(){ + if (this.extraForm.frmName in this.objForm.controls && this.objForm.get(this.extraForm.frmName).value != null && this.objForm.get(this.extraForm.frmName).value.length != 0 ){ + this.hideForm = false + this.objForm.valid + } else { + this.hideForm = true + } +} + getConfigFromBtnSelect(event) { // this.obj.specific == undefined ? (this.obj.specific = {}) : null; // TODO: Ajout de tous les id_parents ["id_sites_groups" etc ] dans l'objet obj.dataComplement diff --git a/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html index cd9a5bcd3..9f1edcf9f 100644 --- a/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html +++ b/frontend/app/components/monitoring-sites-create/monitoring-sites-create.component.html @@ -8,6 +8,7 @@
diff --git a/frontend/app/components/monitoring-visits/monitoring-visits.component.html b/frontend/app/components/monitoring-visits/monitoring-visits.component.html index 704a945a9..db5d49214 100644 --- a/frontend/app/components/monitoring-visits/monitoring-visits.component.html +++ b/frontend/app/components/monitoring-visits/monitoring-visits.component.html @@ -20,6 +20,7 @@ *ngIf="bEdit" [(bEdit)]="bEdit" [apiService]="siteService" + [isExtraForm]="true" > }) => { this._objService.changeSelectedObj(data.site, true); this.site = data.site; + this.types_site = data.site['types_site'] this.setVisits(data.visits); this.baseFilters = { id_base_site: this.site.id_base_site }; }); @@ -163,7 +164,8 @@ export class MonitoringVisitsComponent extends MonitoringGeomComponent implement } initValueToSend(){ - return this.site['types_site'] + this.initSiteVisit() + return this.types_site } updateForm(){ diff --git a/frontend/app/gnModule.module.ts b/frontend/app/gnModule.module.ts index 0a4d64b09..6391f20ea 100644 --- a/frontend/app/gnModule.module.ts +++ b/frontend/app/gnModule.module.ts @@ -55,7 +55,7 @@ import { BtnSelectComponent } from "./components/btn-select/btn-select.component import { MonitoringSitesEditComponent } from "./components/monitoring-sites-edit/monitoring-sites-edit.component"; import { MonitoringVisitsComponent } from "./components/monitoring-visits/monitoring-visits.component"; import { OptionListButtonComponent } from "./components/option-list-btn/option-list-btn.component"; - +import { MatErrorMessagesDirective } from './utils/matErrorMessages.directive'; // my module routing const routes: Routes = [ /** modules */ @@ -137,6 +137,7 @@ const routes: Routes = [ BtnSelectComponent, MonitoringVisitsComponent, OptionListButtonComponent, + MatErrorMessagesDirective ], imports: [ GN2CommonModule, diff --git a/frontend/app/interfaces/object.ts b/frontend/app/interfaces/object.ts index cec2af00d..603c59db8 100644 --- a/frontend/app/interfaces/object.ts +++ b/frontend/app/interfaces/object.ts @@ -1,3 +1,4 @@ +import { AbstractControl } from "@angular/forms"; import { JsonData } from "../types/jsondata"; import { IPaginated } from "./page"; import { GeoJSON } from "geojson"; @@ -23,3 +24,5 @@ export type SelectObject = { label: string; }; + +export type IExtraForm = {frmCtrl :AbstractControl,frmName:string} diff --git a/frontend/app/services/form.service.ts b/frontend/app/services/form.service.ts index c8d6b0ff5..0798b10df 100644 --- a/frontend/app/services/form.service.ts +++ b/frontend/app/services/form.service.ts @@ -3,23 +3,29 @@ import { BehaviorSubject, Observable, forkJoin, of } from 'rxjs'; import { concatMap } from 'rxjs/operators'; import { ISite, ISitesGroup } from '../interfaces/geom'; -import { IobjObs, ObjDataType } from '../interfaces/objObs'; import { JsonData } from '../types/jsondata'; import { Utils } from '../utils/utils'; import { MonitoringObjectService } from './monitoring-object.service'; +import { FormControl } from '@angular/forms'; +import { IExtraForm } from '../interfaces/object'; + @Injectable() export class FormService { data: JsonData = {}; + frmCtrl: FormControl = new FormControl(null); + frmCtrlName: string = ''; private dataSub = new BehaviorSubject(this.data); + private formCtrl = new BehaviorSubject({frmCtrl : this.frmCtrl,frmName:this.frmCtrlName}); currentData = this.dataSub.asObservable(); + currentExtraFormCtrl = this.formCtrl.asObservable(); properties: JsonData = {}; moduleCode: string; objecType: string; constructor(private _objService: MonitoringObjectService) {} - // TODO: voir si nécessaire de garder ça (objService permet d'avoir le bon objet ? et sinon modifier pour obtenir ce qu'il faut en formulaire) + changeDataSub( newDat: JsonData, objectType: string, @@ -40,6 +46,10 @@ export class FormService { this.dataSub.next(newDat); } + changeExtraFormControl(formCtrl:FormControl,formCtrlName:string){ + this.formCtrl.next({frmCtrl:formCtrl,frmName:formCtrlName}) + } + formValues(obj): Observable { // const {properties ,remainaing} = obj const properties = Utils.copy(this.properties); diff --git a/frontend/app/utils/matErrorMessages.directive.ts b/frontend/app/utils/matErrorMessages.directive.ts new file mode 100644 index 000000000..66d8b53c8 --- /dev/null +++ b/frontend/app/utils/matErrorMessages.directive.ts @@ -0,0 +1,37 @@ +import { Component, AfterViewInit, Injector } from '@angular/core'; +import {MatInput } from '@angular/material/input'; +import { MatFormFieldControl,MatFormField } from '@angular/material/form-field'; + +@Component({ + selector: '[matErrorMessages]', + template: '{{ error }}' +}) +export class MatErrorMessagesDirective implements AfterViewInit { + error = ''; + inputRef: MatFormFieldControl; + + constructor(private _inj: Injector) { } + + // Setup all initial tooling + ngAfterViewInit() { + // grab reference to MatFormField directive, where form control is accessible. + let container = this._inj.get(MatFormField); + this.inputRef = container._control; + + // sub to the control's status stream + this.inputRef.ngControl.statusChanges.subscribe(this.updateErrors); + } + + // This grabs a single active error instead of multiple. + private updateErrors = (state: 'VALID' | 'INVALID') => { + if (state === 'INVALID') { + let controlErrors = this.inputRef.ngControl.errors; + const firstError = Object.keys(controlErrors)[0]; + if(firstError === 'required') + this.error = 'Ce champs est requis.'; + + if(firstError === 'minlength') + this.error = 'Vous devez choisir au moins une valeur.'; + } + } +} \ No newline at end of file