Skip to content

Commit 1714776

Browse files
committed
🐛 fix: Handle non selected lists
1 parent 9bd87a9 commit 1714776

File tree

8 files changed

+84
-32
lines changed

8 files changed

+84
-32
lines changed

dev/app.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
| Delete
1919

2020
.errors.text-center
21-
div.alert.alert-danger(v-for="item in validationErrors") {{ item.field.label}}:
21+
div.alert.alert-danger(v-for="item in validationErrors", track-by="$index") {{ item.field.label}}:
2222
strong {{ item.error }}
2323

2424
vue-form-generator(:schema='schema', :model='model', :options='formOptions', :multiple="selected.length > 1", v-ref:form, :is-new-model="isNewModel")

dev/schema.js

+16-11
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,26 @@ module.exports = {
120120
type: "masked",
121121
label: "Mobile",
122122
model: "mobile",
123-
mask: "(99) 999-9999"
123+
mask: "(99) 999-9999",
124+
validator: validators.required
124125
},
125126
{
126127
type: "spectrum",
127128
label: "Color",
128129
model: "favoriteColor",
130+
required: true,
129131
colorOptions: {
130132
//preferredFormat: "rgb"
131-
}
133+
},
134+
validator: validators.required
132135
},
133136
{
134137
type: "image",
135138
label: "Avatar",
136139
model: "avatar",
137-
browse: true
140+
required: true,
141+
browse: true,
142+
validator: validators.required
138143

139144
},
140145
{
@@ -157,6 +162,7 @@ module.exports = {
157162
label: "DOB",
158163
model: "dob",
159164
multi: true,
165+
required: true,
160166
placeholder: "User's birth of date",
161167
min: moment("1900-01-01").toDate(),
162168
max: moment("2016-01-01").toDate(),
@@ -208,13 +214,11 @@ module.exports = {
208214
multi: true,
209215
min: 1,
210216
max: 10,
217+
required: true,
211218
sliderOptions: {
212219
grid: true
213220
},
214-
validator: [
215-
validators.integer,
216-
validators.number
217-
]
221+
validator: validators.integer
218222
},
219223

220224
{
@@ -244,7 +248,7 @@ module.exports = {
244248
{ id: "it", name: "Italic" },
245249
{ id: "fr", name: "French" }
246250
],
247-
default: "en_GB"
251+
validator: validators.required
248252
},
249253
{
250254
type: "selectEx",
@@ -253,13 +257,14 @@ module.exports = {
253257
multi: true,
254258
required: true,
255259
values: faker.definitions.address.country,
256-
default: "United Kingdom",
260+
//default: "United Kingdom",
257261
multiSelect: false,
258262
selectOptions: {
259263
// https://silviomoreto.github.io/bootstrap-select/options/
260264
liveSearch: true,
261265
size: 10
262-
}
266+
},
267+
validator: validators.required
263268
},
264269
{
265270
type: "text",
@@ -351,7 +356,7 @@ module.exports = {
351356
{ id: "user", name: "Registered User"},
352357
{ id: "visitor", name: "Visitor"}
353358
],
354-
default: null
359+
validator: validators.required
355360
},
356361
{
357362
type: "label",

src/fields/fieldSelect.vue

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template lang="jade">
22
select.form-control(v-model="value", :disabled="disabled")
3+
option(:disabled="schema.required", :value="null", :selected="value == undefined") &lt;Not selected&gt;
34
option(v-for="item in items", :value="getItemID(item)") {{ getItemName(item) }}
45
</template>
56

src/fields/fieldSelectEx.vue

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template lang="jade">
22
select.selectpicker(v-model="value", :disabled="disabled", :multiple="schema.multiSelect", :title="schema.placeholder", data-width="100%")
3+
option(:disabled="schema.required", v-if="schema.multiSelect !== true", :value="null", :selected="value == undefined") &lt;Not selected&gt;
34
option(v-for="item in items", :value="getItemID(item)") {{ getItemName(item) }}
45
</template>
56

src/formGenerator.vue

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
button.btn.btn-default(v-for="btn in field.buttons", @click="btn.onclick(model, field)", :class="btn.classes") {{ btn.label }}
1616
.hint(v-if="field.hint") {{ field.hint }}
1717
.errors(v-if="field.errors && field.errors.length > 0")
18-
span(v-for="error in field.errors") {{ error }}
18+
span(v-for="error in field.errors", track-by="$index") {{ error }}
1919
</template>
2020

2121
<script>
@@ -65,7 +65,11 @@
6565
6666
watch: {
6767
// new model loaded
68-
model: function() {
68+
model: function(newModel, oldModel) {
69+
if (oldModel == newModel) // model got a new property
70+
return;
71+
72+
console.log("Model changed!");
6973
if (this.options.validateAfterLoad === true && this.isNewModel !== true)
7074
this.validate();
7175
else

src/utils/validators.js

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ function checkEmpty(value, required) {
1313

1414
module.exports = {
1515

16+
required(value, field) {
17+
return checkEmpty(value, field.required);
18+
},
19+
1620
number(value, field) {
1721
let res = checkEmpty(value, field.required); if (res != null) return res;
1822

test/unit/specs/fields/fieldSelect.spec.js

+26-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe("fieldSelect.vue", () => {
2020
type: "select",
2121
label: "Cities",
2222
model: "city",
23+
required: false,
2324
values: [
2425
"London",
2526
"Paris",
@@ -46,11 +47,17 @@ describe("fieldSelect.vue", () => {
4647

4748
it("should contain option elements", () => {
4849
let options = input.querySelectorAll("option");
49-
expect(options.length).to.be.equal(4);
50+
expect(options.length).to.be.equal(4 + 1); // +1 for <non selected>
5051

51-
expect(options[1].value).to.be.equal("Paris");
52-
expect(options[1].textContent).to.be.equal("Paris");
53-
expect(options[1].selected).to.be.true;
52+
expect(options[2].value).to.be.equal("Paris");
53+
expect(options[2].textContent).to.be.equal("Paris");
54+
expect(options[2].selected).to.be.true;
55+
});
56+
57+
it("should contain a <non selected> element", () => {
58+
let options = input.querySelectorAll("option");
59+
expect(options[0].disabled).to.be.false;
60+
expect(options[0].textContent).to.be.equal("<Not selected>");
5461
});
5562

5663
it("should contain the value", (done) => {
@@ -88,6 +95,16 @@ describe("fieldSelect.vue", () => {
8895

8996
});
9097

98+
it("should contain a disabled <non selected> element if required", (done) => {
99+
schema.required = true;
100+
vm.$nextTick( () => {
101+
let options = input.querySelectorAll("option");
102+
expect(options[0].disabled).to.be.true;
103+
expect(options[0].textContent).to.be.equal("<Not selected>");
104+
done();
105+
});
106+
});
107+
91108
});
92109

93110
describe("check static values with { id, name } objects", () => {
@@ -112,12 +129,12 @@ describe("fieldSelect.vue", () => {
112129

113130
it("should contain option elements", () => {
114131
let options = input.querySelectorAll("option");
115-
expect(options.length).to.be.equal(4);
132+
expect(options.length).to.be.equal(4 + 1); // +1 for <non selected>
116133

117-
expect(options[1].value).to.be.equal("2");
118-
expect(options[1].textContent).to.be.equal("Paris");
119-
expect(options[1].selected).to.be.true;
120-
expect(options[0].selected).to.be.false;
134+
expect(options[2].value).to.be.equal("2");
135+
expect(options[2].textContent).to.be.equal("Paris");
136+
expect(options[2].selected).to.be.true;
137+
expect(options[1].selected).to.be.false;
121138
});
122139

123140
it("should contain the value", (done) => {

test/unit/specs/fields/fieldSelectEx.spec.js

+29-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe("fieldSelectEx.vue", () => {
2020
label: "Cities",
2121
model: "city",
2222
multiSelect: false,
23+
required: false,
2324
values: [
2425
"London",
2526
"Paris",
@@ -47,13 +48,19 @@ describe("fieldSelectEx.vue", () => {
4748

4849
it("should contain option elements", () => {
4950
let options = input.querySelectorAll("option");
50-
expect(options.length).to.be.equal(4);
51+
expect(options.length).to.be.equal(4 + 1); // +1 for <non selected>
5152

52-
expect(options[1].value).to.be.equal("Paris");
53-
expect(options[1].textContent).to.be.equal("Paris");
54-
expect(options[1].selected).to.be.true;
53+
expect(options[2].value).to.be.equal("Paris");
54+
expect(options[2].textContent).to.be.equal("Paris");
55+
expect(options[2].selected).to.be.true;
5556
});
5657

58+
it("should contain a <non selected> element", () => {
59+
let options = input.querySelectorAll("option");
60+
expect(options[0].disabled).to.be.false;
61+
expect(options[0].textContent).to.be.equal("<Not selected>");
62+
});
63+
5764
it("should contain the value", (done) => {
5865
vm.$nextTick( () => {
5966
expect(input.value).to.be.equal("Paris");
@@ -89,10 +96,23 @@ describe("fieldSelectEx.vue", () => {
8996

9097
});
9198

99+
it("should contain a disabled <non selected> element if required", (done) => {
100+
schema.required = true;
101+
vm.$nextTick( () => {
102+
let options = input.querySelectorAll("option");
103+
//expect(options[0].disabled).to.be.true;
104+
expect(options[0].textContent).to.be.equal("<Not selected>");
105+
done();
106+
});
107+
});
108+
92109
it("should not be multiple", (done) => {
93110
schema.multiSelect = true;
94111
vm.$nextTick( () => {
95112
expect(input.multiple).to.be.true;
113+
let options = input.querySelectorAll("option");
114+
expect(options.length).to.be.equal(4); // no <non selected>
115+
96116
done();
97117
});
98118
});
@@ -121,12 +141,12 @@ describe("fieldSelectEx.vue", () => {
121141

122142
it("should contain option elements", () => {
123143
let options = input.querySelectorAll("option");
124-
expect(options.length).to.be.equal(4);
144+
expect(options.length).to.be.equal(4 + 1); // +1 for <non selected>
125145

126-
expect(options[1].value).to.be.equal("2");
127-
expect(options[1].textContent).to.be.equal("Paris");
128-
expect(options[1].selected).to.be.true;
129-
expect(options[0].selected).to.be.false;
146+
expect(options[2].value).to.be.equal("2");
147+
expect(options[2].textContent).to.be.equal("Paris");
148+
expect(options[2].selected).to.be.true;
149+
expect(options[1].selected).to.be.false;
130150
});
131151

132152
it("should contain the value", (done) => {

0 commit comments

Comments
 (0)