An error occurred while loading the file. Please try again.
-
Grand Francois authored
- séparation flag de validité UI/modèle - séparation message d'erreur UI/modèle - ajout méthode publique validate() - amélioration des l'initialisation
de966801
import { Input, Output, EventEmitter } from "@angular/core";
import { BaseComponent } from "../base/base.component";
/*
exemple de template :
<div class="md-form form-sm">
<input mdbActive type="text" id="form1" class="form-control" [disabled]="isDisabled" [ngModel]="uiValue" (ngModelChange)="setUIValue($event)">
<label for="form1">{{_title}}</label>
<small class="text-danger">{{_message}}</small>
</div>
*/
/**
* 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 extends BaseComponent {
/**
* 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<any>();
/**
* valeur saisie.
* Cette variable n'est modifiée que lorsqu'on affecte le modèle ou que l'utilisateur fait une saisie
*/
private _uiValue: string;
/**
* 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 _isValidUI = false;
/**
* 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 _isValidModel = false;
/**
* message d'erreur UI
*/
private _errorMessageUI: string;
/**
* message d'erreur modèle
*/
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
private _errorMessageModel: string;
private get isDisabled(): boolean {
return this._inputDisabled;
}
/**
* é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._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 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() {
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
this.onChange.emit({ "action": "model", "value": this.getModelValue() });
}
private setAndValidateModel(v: any) {
this.setModelValue(v);
this.emitModelChanged();
this.validateModel();
}
public set model(v: any) {
this.setAndValidateModel(v);
// MAJ UI
this._uiValue = this.modelToUI(this.getModelValue());
this.validateUI();
}
private get uiValue() {
return this._uiValue;
}
/*
* fonction appelée lorsque l'utilisateur fait une saisie
* @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
*/
protected afterFirstViewChecked() {
this._uiValue = this.modelToUI(this.getModelValue());
this.validate();
}
/**
* retourne la valeur du modèle
*/
protected abstract getModelValue(): any;
/**
* affecte la valeur du modèle
*/
protected abstract setModelValue(v: any);
/**
* valide une valeur de modèle : est ce une valeur acceptable ? (par ex, nombre dans un intervalle, valeur dans une liste, ...)
* @param v valide la valeur du modèle
* @returns isValid : true si la valeur est valide, false sinon
* @returns message : message d'erreur
*/
protected abstract validateModelValue(v: any): { isValid: boolean, message: string };
/**
* convertit le modèle en valeur affichable par l'UI
*/
protected abstract modelToUI(v: any): string;
/**
* valide une valeur saisie dans l'UI (forme de la saisie : est ce bien une date, un nombre, ...)
* @param ui valide la valeur saisie
* @returns isValid : true si la valeur est valide, false sinon
* @returns message : message d'erreur
*/
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
protected abstract validateUIValue(ui: string): { isValid: boolean, message: string };
/**
* convertit une valeur saisie dans l'UI en valeur affectable au modèle
*/
protected abstract uiToModel(ui: string): any;
}
/*
* exemple d'utilisation de GenericInputComponent
*/
/*
import { Component } from "@angular/core";
import { NumericalString, Message } from "jalhyd";
@Component({
selector: "test-input",
template: `<div class="md-form form-sm">
<input mdbActive type="text" id="form1" class="form-control" [disabled]="isDisabled" [ngModel]="uiValue" (ngModelChange)="setUIValue($event)">
<label for="form1">{{_title}}</label>
<small class="text-danger">{{_message}}</small>
</div>`
})
export class TestInputComponent extends GenericInputComponent {
private _model: number;
constructor() {
super();
this._model = 0;
}
protected getModelValue(): any {
return this._model;
}
protected setModelValue(v: any) {
this._model = v;
}
protected validateModelValue(v: any): { isValid: boolean, message: string } {
let msg = undefined;
let valid = false;
if (v < 0)
msg = "La valeur n'est pas >= 0 ";
else
valid = true;
return { isValid: valid, message: msg };
}
protected modelToUI(v: any): string {
if (typeof (v) == "number")
return String(v);
return undefined;
}
protected validateUIValue(ui: string): { isValid: boolean, message: string } {
let valid: boolean = false;
let msg: string = undefined;
let v: NumericalString = new NumericalString(ui);
if (!v.isNumerical)
msg = "Veuillez entrer une valeur numérique";
else
valid = true;
return { isValid: valid, message: msg };
281282283284285286287288
}
protected uiToModel(ui: string): any {
return +ui;
}
}
/**/