diff --git a/src/app/components/base-param-input/base-param-input.component.html b/src/app/components/base-param-input/base-param-input.component.html
deleted file mode 100644
index 2e1af91be2ee365ae2d2697b4adf14c634696f9a..0000000000000000000000000000000000000000
--- a/src/app/components/base-param-input/base-param-input.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div class="md-form form-sm">
-    <input mdbActive type="text" id="form1" class="form-control" [ngModel]="_uiValue.uncheckedValueString" (ngModelChange)="setValue($event)">
-    <label for="form1">{{_title}}</label>
-    <small class="text-danger">{{_message}}</small>
-</div>
\ No newline at end of file
diff --git a/src/app/components/base-param-input/base-param-input.component.ts b/src/app/components/base-param-input/base-param-input.component.ts
index 1006d13f3cd9462212e16af9712a7f0d241efa79..0eb9720084afa35a3f2006bda07b460f50e3cd8c 100644
--- a/src/app/components/base-param-input/base-param-input.component.ts
+++ b/src/app/components/base-param-input/base-param-input.component.ts
@@ -7,6 +7,7 @@ import { BaseParam, NumericalString, Message, ParamDomain, ParamDomainValue } fr
 
 import { InternationalisationService, LanguageCode } from "../../services/internationalisation/internationalisation.service";
 import { Observable } from "../../services/observer";
+import { GenericInputComponent } from "../generic-input/generic-input.component";
 
 export class NgBaseParam extends Observable {
     private _param: BaseParam;
@@ -40,179 +41,68 @@ export class NgBaseParam extends Observable {
 
 @Component({
     selector: "base-param-input",
-    templateUrl: "./base-param-input.component.html",
-    providers: [
-        {
-            provide: NG_VALUE_ACCESSOR,
-            useExisting: forwardRef(() => BaseParamInputComponent),
-            multi: true
-        },
-        {
-            provide: NG_VALIDATORS,
-            useExisting: forwardRef(() => BaseParamInputComponent),
-            multi: true
-        }
-    ]
+    templateUrl: "../generic-input/generic-input.component.html",
 })
-export class BaseParamInputComponent implements ControlValueAccessor, DoCheck {
-    /**
-     * enable/disable input field
-     */
-    @Input('inputDisabled')
-    private _inputDisabled: boolean;
-
+export class BaseParamInputComponent extends GenericInputComponent {
     /**
      * managed parameter
      */
     @Input('param')
     private _paramDef: NgBaseParam;
 
-    @Input('title')
-    private _title: string;
-
-    private _message: string;
-
-    /**
-     * flag d'affichage du titre
-     */
-    public displayTitle: boolean = false;
-
-    /**
-     * true si la modification du paramètre géré vient de l'interface utilisateur
-     * false si la modification du paramètre géré vient d'un appel du code
-     */
-    private _fromUI: boolean;
-
-    /**
-     * valeur dans le contrôle (saisie par l'utilisateur)
-     */
-    private _uiValue: NumericalString;
-
-    constructor(private changeDetector: ChangeDetectorRef, private intlService: InternationalisationService) {
-        this._uiValue = new NumericalString();
-    }
-
-    /**
-     * fonction appelée lorsque l'utilisateur fait une saisie
-     * @param event valeur du contrôle
-     */
-    private setValue(event: any) {
-        this._fromUI = true;
-        this._uiValue.value = event;
-        // this.log(this._uiValue.toString());
-        return this.validateUIValue();
+    constructor(private intlService: InternationalisationService) {
+        super();
     }
 
-    /**
-     * fonction appelée lors d'un rafraîchissement de l'UI
-     */
-    ngDoCheck(): void {
-        // this.log("ngDoCheck start : " + this.getSParam() + this.getSUIvalue() + this.getSfromUI());
-
-        if (this._fromUI)
-            this.updateMessage(this._uiValue);
-        else {
-            if (this._paramDef.isDefined) {
-                this.updateMessage(new NumericalString(this._paramDef.getValue()));
-                this._uiValue.value = String(this._paramDef.getValue());
-            }
-            else
-                this.updateMessage(this._uiValue);
-        }
-
-        // this.log("ngDoCheck end : " + this.getSParam() + this.getSUIvalue());
-
-        this._fromUI = false;
+    protected getModelValue(): any {
+        return this._paramDef.getValue();
     }
 
-    private updateMessage(v: NumericalString) {
-        // this.log("updateMessage start :" + this.getSParam() + this.getSfromUI() + this.getSUIvalue(v) + "  message=" + this._message);
-
-        if (v.isNumerical) {
-            this._message = undefined;
-
-            try {
-                this._paramDef.checkValue(v.numericalValue);
-            }
-            catch (e) {
-                if (e instanceof Message)
-                    this._message = this.intlService.localizeMessage(e);
-                else
-                    this._message = "invalid value";
-            }
+    protected setModelValue(v: any) {
+        try {
+            this._paramDef.setValue(v);
         }
-        else {
-            switch (this.intlService.currentLanguage.code) {
-                case LanguageCode.FRENCH:
-                    this._message = "Veuillez entrer une valeur numérique";
-                    break;
-
-                default:
-                    this._message = "Please enter a numerical value";
-            }
+        catch (e) {
+            // géré par validateModelValue()
         }
-
-        // this.log("updateMessage end :" + this.getSParam() + this.getSfromUI() + this.getSUIvalue(v) + "  message=" + this._message);
     }
 
-    private validateUIValue() {
-        // this.log("");
-        // this.log("validateValue start : val '" + this._uiValue.toString() + "'" + this.getSParam() + this.getSfromUI());
-
-        let ok: boolean = this._uiValue.isNumerical;
-        if (ok) {
-            try {
-                if (!this._paramDef.isDefined || this._paramDef.getValue() != this._uiValue.numericalValue) {
-                    this._paramDef.setValue(this._uiValue.numericalValue);
-                    this.changeDetector.detectChanges();  // provoque une détection des changements dans les contrôles
-                }
-            }
-            catch (e) {
-                ok = false;
-            }
-        }
+    protected validateModelValue(v: any): { isValid: boolean, message: string } {
+        let msg = undefined;
+        let valid = false;
 
-        if (!ok) {
-            // this.log("validateValue end : " + this.getSParam());
-
-            let err = {
-                rangeError: {
-                    // given: val,
-                    given: this._uiValue.toString(),
-                    max: 4,
-                    min: 0
-                }
-            };
-            return err;
+        try {
+            this._paramDef.checkValue(v);
+            valid = true;
+        }
+        catch (e) {
+            if (e instanceof Message)
+                msg = this.intlService.localizeMessage(e);
+            else
+                msg = "invalid value";
         }
 
-        // this.log("validateValue end : " + this.getSParam());
-        return null;
+        return { isValid: valid, message: msg };
     }
 
-    // private log(m: string) {
-    //     console.log("ParamInputComponent(" + this._id + ") : " + m);
-    // }
+    protected modelToUI(v: any): string {
+        return String(v);
+    }
 
-    // ControlValueAccessor interface
+    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
+        let valid: boolean = false;
+        let msg: string = undefined;
 
-    propagateChange = (_: any) => { };
+        let v: NumericalString = new NumericalString(ui);
+        if (!v.isNumerical)
+            msg = "Veuillez entrer une valeur numérique";
+        else
+            valid = true;
 
-    /*
-    //From ControlValueAccessor interface
-    writeValue(value: any) {
-        if (value !== this.innerValue) {
-            this.innerValue = value;
-        }
-    }
-    */
-    writeValue(value: any) {
-        // this.log("writeValue " + value);
+        return { isValid: valid, message: msg };
     }
 
-    registerOnChange(fn: any) {
-        this.propagateChange = fn;
+    protected uiToModel(ui: string) {
+        return +ui;
     }
-
-    registerOnTouched() { }
 }