From de9668015d65f8231f3e27701f8a8507338c26c8 Mon Sep 17 00:00:00 2001 From: "francois.grand" <francois.grand@irstea.fr> Date: Wed, 24 Jan 2018 09:27:43 +0100 Subject: [PATCH] =?UTF-8?q?remaniement=20de=20la=20classe=20GenericInputCo?= =?UTF-8?q?mponent=20-=20s=C3=A9paration=20flag=20de=20validit=C3=A9=20UI/?= =?UTF-8?q?mod=C3=A8le=20-=20s=C3=A9paration=20message=20d'erreur=20UI/mod?= =?UTF-8?q?=C3=A8le=20-=20ajout=20m=C3=A9thode=20publique=20validate()=20-?= =?UTF-8?q?=20am=C3=A9lioration=20des=20l'initialisation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generic-input.component.html | 4 +- .../generic-input/generic-input.component.ts | 160 +++++++++++++----- 2 files changed, 117 insertions(+), 47 deletions(-) diff --git a/src/app/components/generic-input/generic-input.component.html b/src/app/components/generic-input/generic-input.component.html index afdbb5946..a34a609b9 100644 --- a/src/app/components/generic-input/generic-input.component.html +++ b/src/app/components/generic-input/generic-input.component.html @@ -1,6 +1,6 @@ <div class="md-form form-sm"> - <input mdbActive type="text" id="form1" class="form-control" [disabled]="isDisabled" [ngModel]="uiValue" (ngModelChange)="setUIValue($event)"> + <input mdbActive type="text" id="form1" class="form-control" [disabled]="isDisabled" [(ngModel)]="uiValue"> <!-- on utilise [innerHTML] pour que les codes HTML comme soient interprétés correctement --> <label for="form1" [innerHTML]="_title"></label> - <small class="text-danger" [innerHTML]="_message"></small> + <small *ngIf="showError" class="text-danger" [innerHTML]="errorMessage"></small> </div> \ No newline at end of file diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts index a073b4a43..2077a6bbb 100644 --- a/src/app/components/generic-input/generic-input.component.ts +++ b/src/app/components/generic-input/generic-input.component.ts @@ -1,4 +1,6 @@ -import { Input, Output, EventEmitter, OnInit } from "@angular/core"; +import { Input, Output, EventEmitter } from "@angular/core"; + +import { BaseComponent } from "../base/base.component"; /* exemple de template : @@ -12,101 +14,169 @@ exemple de template : /** * classe de gestion générique d'un champ de saisie avec titre, validation et message d'erreur + * définitions : + * - modèle : valeur gérée, indépendement de la façon dont elle est affichée + * - UI : interface utilisateur, présentation de la valeur gérée */ -export abstract class GenericInputComponent { //implements OnInit { +export abstract class GenericInputComponent extends BaseComponent { /** - * enable/disable input field + * flag de désactivation de l'input */ @Input('inputDisabled') private _inputDisabled: boolean = false; + /** + * flag d'affichage du message d'erreur + */ + public showError = true; + /** * chaîne affichée dans l'input quand aucune valeur n'est saisie */ @Input('title') private _title: string; + /** + * événement signalant un changement : valeur du modèle, validité, ... + */ @Output() - protected onChange = new EventEmitter<string>(); + protected onChange = new EventEmitter<any>(); /** - * validité actuelle (false si erreur dûe à la saisie ou à la valeur du modèle) + * valeur saisie. + * Cette variable n'est modifiée que lorsqu'on affecte le modèle ou que l'utilisateur fait une saisie */ - private _isValid; + private _uiValue: string; /** - * message d'erreur + * flag de validité de la saisie dans l'UI + * par ex : est ce bien une valeur numérique ? n'y a-t-il que des minuscules ? etc... */ - private _message: string; + private _isValidUI = false; /** - * événement de changement de la valeur du modèle + * flag de validité de la valeur du modèle + * par ex : la valeur saisie fait elle bien partie d'un domaine de définition donné ? date inférieure à une limite ? etc... */ - private emitModelChanged() { - this.onChange.emit("value"); - } + private _isValidModel = false; /** - * événement de changement de la valeur du modèle + * message d'erreur UI */ - private emitValidChanged() { - this.onChange.emit("valid"); - } + private _errorMessageUI: string; + + /** + * message d'erreur modèle + */ + private _errorMessageModel: string; private get isDisabled(): boolean { return this._inputDisabled; } - protected validateModel(): boolean { - let { isValid, message } = this.validateModelValue(this.getModelValue()); - this._message = message; - this.setValid(isValid); - return isValid; + /** + * événement de changement de la validité de la saisie + */ + private emitValidChanged() { + this.onChange.emit({ "action": "valid", "value": this.isValid }); } + /** + * calcul de la validité globale du composant (UI+modèle) + */ public get isValid() { - return this._isValid; + return this._isValidUI && this._isValidModel; + } + + private setUIValid(b: boolean) { + const old = this.isValid; + this._isValidUI = b; + if (this.isValid != old) + this.emitValidChanged(); + } + + private validateUI() { + let { isValid, message } = this.validateUIValue(this._uiValue); + this._errorMessageUI = message; + this.setUIValid(isValid); + return isValid; } - private setValid(b: boolean) { - if (this._isValid != b) { - this._isValid = b; + private setModelValid(b: boolean) { + const old = this.isValid; + this._isValidModel = b; + if (this.isValid != old) this.emitValidChanged(); - } + } + + private validateModel() { + let { isValid, message } = this.validateModelValue(this.getModelValue()); + this._errorMessageModel = message; + this.setModelValid(isValid); + } + + public validate() { + this.validateUI(); + this.validateModel(); + } + + /** + * getter du message d'erreur affiché. + * L'erreur de forme (UI) est prioritaire + */ + private get errorMessage() { + if (this._errorMessageUI != undefined) + return this._errorMessageUI; + return this._errorMessageModel; } public get model(): any { return this.getModelValue(); } + /** + * événement de changement de la valeur du modèle + */ + private emitModelChanged() { + this.onChange.emit({ "action": "model", "value": this.getModelValue() }); + } + + private setAndValidateModel(v: any) { + this.setModelValue(v); + this.emitModelChanged(); + + this.validateModel(); + } + public set model(v: any) { - if (this.model !== v) { - this.setModelValue(v); - this.emitModelChanged(); - let { isValid, message } = this.validateModelValue(v); - this._message = message; - this.setValid(isValid); - } - } - - private validateUI(ui: string) { - let { isValid, message } = this.validateUIValue(ui); - this._message = message; - this.setValid(isValid); - return isValid; + this.setAndValidateModel(v); + + // MAJ UI + this._uiValue = this.modelToUI(this.getModelValue()); + this.validateUI(); } private get uiValue() { - return this.modelToUI(this.getModelValue()); + return this._uiValue; } /* * fonction appelée lorsque l'utilisateur fait une saisie - * @param event valeur du contrôle + * @param ui valeur dans le contrôle + */ + private set uiValue(ui: any) { + this._uiValue = ui; + if (this.validateUI()) + this.setAndValidateModel(this.uiToModel(ui)); + } + + /** + * appelé après le 1er affichage du composant + * @see BaseComponent */ - private setUIValue(ui: any) { - if (this.validateUI(ui)) - this.model = this.uiToModel(ui); + protected afterFirstViewChecked() { + this._uiValue = this.modelToUI(this.getModelValue()); + this.validate(); } /** -- GitLab