diff --git a/.vscode/launch.json b/.vscode/launch.json
index 560298a3045c52d0ab3ab4eaeeec40ee183c8432..1d92791fcaaab47792e582858c23e003bd0b8cb0 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -10,7 +10,10 @@
             "name": "Launch Chrome (local webserver)",
             "url": "http://localhost:4200",
             "webRoot": "${workspaceFolder}",
-            "runtimeExecutable": "/usr/bin/chromium-browser"
+            "runtimeExecutable": "/usr/bin/chromium",
+            "runtimeArgs": [
+                "--preserve-symlinks"
+            ]
         },
         {
             "name": "Launch Firefox (local webserver)",
@@ -19,6 +22,23 @@
             "reAttach": true,
             "url": "http://localhost:4200",
             "webRoot": "${workspaceFolder}"
+        },
+        {
+            "name": "Launch e2e current file",
+            "type": "node",
+            "request": "launch",
+            "stopOnEntry": false,
+            "program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
+            "args": [
+                "${workspaceRoot}/protractor.conf.js",
+                "--specs=${file}"
+            ],
+            "cwd": "${workspaceRoot}",
+            "sourceMaps": true,
+            "outFiles": [
+                "${workspaceRoot}/dist/out-tsc-e2e/*.js"
+            ],
+            "skipSourceMapSupport": true
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/e2e/variable-param-cancel.e2e-spec.ts b/e2e/variable-param-cancel.e2e-spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..750fdd160d73588540e51b7d4bcb64abe0d18b84
--- /dev/null
+++ b/e2e/variable-param-cancel.e2e-spec.ts
@@ -0,0 +1,30 @@
+import { ListPage } from "./list.po";
+import { by, element } from "protractor";
+
+/**
+ * Check that a cancel button is present in min/max/list edition dialog
+ * for variable parameters
+ */
+describe("ngHyd - check cancel button for variable parameters - ", () => {
+    let listPage: ListPage;
+
+    beforeAll(async () => {
+        listPage = new ListPage();
+    });
+
+    fit("when min/max/list values dialog opens, a cancel button should be present", async () => {
+        // start page
+        await listPage.navigateTo();
+
+        // open PAB chute
+        await listPage.clickMenuEntryForCalcType(12);
+
+        // click "var" radio on Z1 parameter
+        const z1btn = element(by.id("mat-button-toggle-2-button"));
+        await z1btn.click();
+
+        // cancel button presence
+        const cancelbtn = element(by.id("btn-cancel"));
+        expect(await cancelbtn.isPresent() && await cancelbtn.isDisplayed()).toBeTruthy();
+    });
+});
diff --git a/jalhyd_branch b/jalhyd_branch
index 626e97d71d9e3364f9abe16f7e3c8d70dea5a7fa..084f9effbcaa415a70f40588672242db178649b2 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-devel
\ No newline at end of file
+300-supprimer-le-champ-_valuemode-dans-paramdefinition
\ No newline at end of file
diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
index 8a454d5c176463e73a6ebf8b8f54c95be76b6121..5fc7c8482a5c80a96117ad4c164b08dd66f6bee5 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
@@ -1,4 +1,5 @@
-<button mat-icon-button id="show-values-chart" (click)="toggleViewChart()" [title]="uitextShowValuesChart">
+<button mat-icon-button id="show-values-chart" (click)="toggleViewChart()" [title]="uitextShowValuesChart"
+    [disabled]="!viewChart && !isFormValid">
     <mat-icon *ngIf="! viewChart">show_chart</mat-icon>
     <mat-icon *ngIf="viewChart">mode_edit</mat-icon>
 </button>
@@ -119,16 +120,11 @@
 </div>
 
 <div mat-dialog-actions [attr.align]="'end'">
-    <div *ngIf="isMinMax || viewChart">
-        <button mat-raised-button [mat-dialog-close]="true" [disabled]="minMaxFormInvalid" cdkFocusInitial>
-            {{ uitextClose }}
-        </button>
-    </div>
-    <div *ngIf="isListe && ! viewChart">
-        <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>
+    <div>
+        <button id="btn-cancel" mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>
             {{ uitextCancel }}
         </button>
-        <button mat-raised-button color="warn" (click)="onValidate()">
+        <button mat-raised-button color="warn" (click)="onValidate()" [disabled]=" !isFormValid">
             {{ uitextValidate }}
         </button>
     </div>
diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
index 3c419f000945cd25d2e946e2d8518ad516727484..d84c85459c6855ab04aabccb30524600103114a9 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
@@ -53,7 +53,7 @@ export class DialogEditParamValuesComponent implements OnInit {
         private fb: FormBuilder,
         @Inject(MAT_DIALOG_DATA) public data: any
     ) {
-        this.param = data.param;
+        this.param = data.param.clone();
         // an explicit ReactiveForm is required for file input component
         const initialValue = (this.param.valueMode === ParamValueMode.LISTE ? this.valuesList : "");
         this.valuesListForm = this.fb.group({
@@ -245,42 +245,56 @@ export class DialogEditParamValuesComponent implements OnInit {
         this.param.setValueList(this, vals);
     }
 
-    /** returns true if min/max/step form is invalid */
-    public get minMaxFormInvalid(): boolean {
-        return this.minMaxForm === undefined || ! this.minMaxForm.valid;
-    }
-
     public toggleViewChart() {
-        // validate list values before switching views ?
-        if (! this.viewChart && this.param.valueMode === ParamValueMode.LISTE) {
-            if (this.onValidate(false)) {
+        // validate values before switching views ?
+        if (!this.viewChart && this.isFormValid) {
                 // toggle
-                this.viewChart = ! this.viewChart;
+            this.viewChart = true;
             }
-        } else {
-            // toggle
-            this.viewChart = ! this.viewChart;
-        }
+        else
+            this.viewChart = false;
+
         // refresh chart when displaying it only
         if (this.viewChart) {
             this.drawChart();
         }
     }
 
-    public onValidate(close = true) {
-        const status = this.validateValuesListString(this.valuesListForm.controls.valuesList.value);
+    /** returns true if form is valid */
+    public get isFormValid(): boolean {
+        var ret: boolean = false;
+        switch (this.param.valueMode) {
+            case ParamValueMode.LISTE:
+                const status = this.validateValuesListString(this.valuesListForm.controls.valuesList.value);
+                ret = status.ok;
+                if (ret) {
+                    this.valuesListForm.controls.valuesList.setErrors(null);
+                    this.valuesList = this.valuesListForm.controls.valuesList.value;
+                }
+                else
+                    this.valuesListForm.controls.valuesList.setErrors({ "model": status.message });
+                break;
 
-        if (status.ok) {
-            this.valuesListForm.controls.valuesList.setErrors(null);
-            this.valuesList = this.valuesListForm.controls.valuesList.value;
-            if (close) {
-                this.dialogRef.close();
-            }
-            return true;
-        } else {
-            this.valuesListForm.controls.valuesList.setErrors({ "model": status.message });
-            return false;
+            case ParamValueMode.MINMAX:
+                ret = this.minMaxForm !== undefined && this.minMaxForm.valid;
+                break;
         }
+        return ret;
+    }
+
+    public onValidate() {
+        switch (this.param.valueMode) {
+            case ParamValueMode.LISTE:
+                this.data.param.setValueList(this, this.param.valueList);
+                break;
+
+            case ParamValueMode.MINMAX:
+                this.data.param.setMinValue(this, this.param.minValue);
+                this.data.param.setMaxValue(this, this.param.maxValue);
+                this.data.param.setStepValue(this, this.param.stepValue);
+                break;
+        }
+        this.dialogRef.close();
     }
 
     /**
@@ -442,10 +456,6 @@ export class DialogEditParamValuesComponent implements OnInit {
         return this.intlService.localizeText("INFO_PARAMFIELD_PASVARIATION");
     }
 
-    public get uitextClose(): string {
-        return this.intlService.localizeText("INFO_OPTION_CLOSE");
-    }
-
     public get uitextCancel(): string {
         return this.intlService.localizeText("INFO_OPTION_CANCEL");
     }
diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts
index 7943071edcf11c5c0b865d0b76cfd1548c9dc700..697667f6c28441a6966d787519633d3970d6d933 100644
--- a/src/app/formulaire/elements/ngparam.ts
+++ b/src/app/formulaire/elements/ngparam.ts
@@ -42,6 +42,14 @@ export class NgParameter extends InputField implements Observer {
         this.disabled = false;
     }
 
+    public clone(): NgParameter {
+        const ret: NgParameter = new NgParameter(this._paramDef.clone(), this.parent);
+        ret._allowEmpty = this._allowEmpty;
+        ret.unit = this.unit;
+        ret.disabled = this.disabled;
+        return ret;
+    }
+
     /**
      * Returns a text preview of the current value(s), depending on the value mode
      * @param compact if true, will represent multiple values in a more compact way