Skip to content

Commit c46fbe3

Browse files
committed
feat: improve handling of option limits
Signed-off-by: Christian Hartmann <chris-hartmann@gmx.de>
1 parent 87fde1c commit c46fbe3

4 files changed

Lines changed: 110 additions & 3 deletions

File tree

lib/Service/FormsService.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ public function getQuestions(int $formId): array {
130130
}
131131
}
132132

133+
// Set `isRequired` if minimum options limit is set
134+
if ($question['type'] === Constants::ANSWER_TYPE_MULTIPLE && $question['extraSettings']['optionsLimitMin'] > 0) {
135+
$question['isRequired'] = true;
136+
}
137+
133138
$questionList[] = $question;
134139
}
135140
} catch (DoesNotExistException $e) {

src/components/Questions/Question.vue

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@
147147
v-html="computedDescription" />
148148
<!-- eslint-enable vue/no-v-html -->
149149
</div>
150+
<NcNoteCard v-if="hasInfo" :id="infoId" type="info">
151+
{{ infoMessage }}
152+
</NcNoteCard>
150153
<NcNoteCard v-if="hasError" :id="errorId" type="error">
151154
{{ errorMessage }}
152155
</NcNoteCard>
@@ -270,6 +273,11 @@ export default {
270273
type: String,
271274
default: null,
272275
},
276+
277+
infoMessage: {
278+
type: String,
279+
default: null,
280+
},
273281
},
274282
275283
emits: [
@@ -329,9 +337,17 @@ export default {
329337
return !!this.errorMessage
330338
},
331339
340+
hasInfo() {
341+
return !!this.infoMessage
342+
},
343+
332344
errorId() {
333345
return `q${this.index}_error`
334346
},
347+
348+
infoId() {
349+
return `q${this.index}_info`
350+
},
335351
},
336352
337353
// Ensure description is sized correctly on initial render

src/components/Questions/QuestionMultiple.vue

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
:contentValid="contentValid"
1212
:shiftDragHandle="shiftDragHandle"
1313
:errorMessage="errorMessage"
14+
:infoMessage="infoMessage"
1415
v-on="commonListeners">
1516
<template #actions>
1617
<NcActionCheckbox
@@ -217,7 +218,7 @@ export default {
217218
},
218219
219220
mixins: [QuestionMixin, QuestionMultipleMixin],
220-
emits: ['update:values'],
221+
emits: ['update:values', 'update:isRequired'],
221222
222223
data() {
223224
return {
@@ -282,6 +283,54 @@ export default {
282283
this.updateOptionsOrder(value, OptionType.Choice)
283284
},
284285
},
286+
287+
availableOptions() {
288+
return (
289+
this.choices.filter(({ text }) => text.trim() !== '').length
290+
+ (this.allowOtherAnswer ? 1 : 0)
291+
)
292+
},
293+
294+
infoMessage() {
295+
const min = this.extraSettings?.optionsLimitMin ?? 0
296+
const max = this.extraSettings?.optionsLimitMax ?? 0
297+
298+
if (!min && !max) {
299+
return null
300+
}
301+
302+
if (min && max) {
303+
if (min === max) {
304+
return n(
305+
'forms',
306+
'Choose exactly one option',
307+
'Choose exactly %n options',
308+
min,
309+
)
310+
}
311+
312+
return t('forms', 'Choose between {min} and {max} options', {
313+
min,
314+
max,
315+
})
316+
}
317+
318+
if (min) {
319+
return n(
320+
'forms',
321+
'Choose at least one option',
322+
'Choose at least %n options',
323+
min,
324+
)
325+
}
326+
327+
return n(
328+
'forms',
329+
'Choose at most one option',
330+
'Choose at most %n options',
331+
max,
332+
)
333+
},
285334
},
286335
287336
watch: {
@@ -306,7 +355,7 @@ export default {
306355
this.errorMessage = n(
307356
'forms',
308357
'You must choose at most one option',
309-
'You must choose a maximum of %n options',
358+
'You must choose at most %n options',
310359
max,
311360
)
312361
return false
@@ -376,6 +425,19 @@ export default {
376425
// For unique (radio) options we cannot set limits, also if null is passed then we need to remove the limit
377426
this.onExtraSettingsChange({ optionsLimitMax: undefined })
378427
} else if (max) {
428+
if (max > this.availableOptions) {
429+
showError(
430+
t(
431+
'forms',
432+
'Upper options limit must not exceed the number of available options',
433+
),
434+
)
435+
this.onExtraSettingsChange({
436+
optionsLimitMax: this.availableOptions || undefined,
437+
})
438+
return
439+
}
440+
379441
if ((this.extraSettings.optionsLimitMin ?? 0) > max) {
380442
showError(
381443
t(
@@ -400,6 +462,19 @@ export default {
400462
if (this.isUnique || min === null) {
401463
this.onExtraSettingsChange({ optionsLimitMin: undefined })
402464
} else if (min) {
465+
if (min > this.availableOptions - 1) {
466+
showError(
467+
t(
468+
'forms',
469+
'Lower options limit must be smaller than the number of available options',
470+
),
471+
)
472+
this.onExtraSettingsChange({
473+
optionsLimitMin: this.availableOptions - 1 || undefined,
474+
})
475+
return
476+
}
477+
403478
if (
404479
this.extraSettings.optionsLimitMax
405480
&& min > this.extraSettings.optionsLimitMax
@@ -413,6 +488,9 @@ export default {
413488
return
414489
}
415490
this.onExtraSettingsChange({ optionsLimitMin: min })
491+
if (min > 0) {
492+
this.$emit('update:isRequired', true)
493+
}
416494
}
417495
},
418496

src/mixins/QuestionMixin.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,16 @@ export default {
217217
return !!this.errorMessage
218218
},
219219

220+
hasInfo() {
221+
return !!this.infoMessage
222+
},
223+
220224
errorId() {
221-
return 'q' + this.index + '_error'
225+
return `q${this.index}_error`
226+
},
227+
228+
infoId() {
229+
return `q${this.index}_info`
222230
},
223231

224232
/**

0 commit comments

Comments
 (0)