diff --git a/lib/Service/FormsService.php b/lib/Service/FormsService.php
index d0e93f5b8..f4a0445e7 100644
--- a/lib/Service/FormsService.php
+++ b/lib/Service/FormsService.php
@@ -130,6 +130,11 @@ public function getQuestions(int $formId): array {
}
}
+ // Set `isRequired` if minimum options limit is set
+ if ($question['type'] === Constants::ANSWER_TYPE_MULTIPLE && $question['extraSettings']['optionsLimitMin'] > 0) {
+ $question['isRequired'] = true;
+ }
+
$questionList[] = $question;
}
} catch (DoesNotExistException $e) {
diff --git a/src/components/Questions/Question.vue b/src/components/Questions/Question.vue
index 4fe673ec0..8b40cbe7d 100644
--- a/src/components/Questions/Question.vue
+++ b/src/components/Questions/Question.vue
@@ -147,6 +147,9 @@
v-html="computedDescription" />
+
+ {{ infoMessage }}
+
{{ errorMessage }}
@@ -270,6 +273,11 @@ export default {
type: String,
default: null,
},
+
+ infoMessage: {
+ type: String,
+ default: null,
+ },
},
emits: [
@@ -329,9 +337,17 @@ export default {
return !!this.errorMessage
},
+ hasInfo() {
+ return !!this.infoMessage
+ },
+
errorId() {
return `q${this.index}_error`
},
+
+ infoId() {
+ return `q${this.index}_info`
+ },
},
// Ensure description is sized correctly on initial render
diff --git a/src/components/Questions/QuestionMultiple.vue b/src/components/Questions/QuestionMultiple.vue
index 50e6741f5..d7f61fdeb 100644
--- a/src/components/Questions/QuestionMultiple.vue
+++ b/src/components/Questions/QuestionMultiple.vue
@@ -11,6 +11,7 @@
:contentValid="contentValid"
:shiftDragHandle="shiftDragHandle"
:errorMessage="errorMessage"
+ :infoMessage="infoMessage"
v-on="commonListeners">
text.trim() !== '').length
+ + (this.allowOtherAnswer ? 1 : 0)
+ )
+ },
+
+ infoMessage() {
+ const min = this.extraSettings?.optionsLimitMin ?? 0
+ const max = this.extraSettings?.optionsLimitMax ?? 0
+
+ if (!min && !max) {
+ return null
+ }
+
+ if (min && max) {
+ if (min === max) {
+ return n(
+ 'forms',
+ 'Choose exactly one option',
+ 'Choose exactly %n options',
+ min,
+ )
+ }
+
+ return t('forms', 'Choose between {min} and {max} options', {
+ min,
+ max,
+ })
+ }
+
+ if (min) {
+ return n(
+ 'forms',
+ 'Choose at least one option',
+ 'Choose at least %n options',
+ min,
+ )
+ }
+
+ return n(
+ 'forms',
+ 'Choose at most one option',
+ 'Choose at most %n options',
+ max,
+ )
+ },
},
watch: {
@@ -306,7 +355,7 @@ export default {
this.errorMessage = n(
'forms',
'You must choose at most one option',
- 'You must choose a maximum of %n options',
+ 'You must choose at most %n options',
max,
)
return false
@@ -376,6 +425,19 @@ export default {
// For unique (radio) options we cannot set limits, also if null is passed then we need to remove the limit
this.onExtraSettingsChange({ optionsLimitMax: undefined })
} else if (max) {
+ if (max > this.availableOptions) {
+ showError(
+ t(
+ 'forms',
+ 'Upper options limit must not exceed the number of available options',
+ ),
+ )
+ this.onExtraSettingsChange({
+ optionsLimitMax: this.availableOptions || undefined,
+ })
+ return
+ }
+
if ((this.extraSettings.optionsLimitMin ?? 0) > max) {
showError(
t(
@@ -400,6 +462,19 @@ export default {
if (this.isUnique || min === null) {
this.onExtraSettingsChange({ optionsLimitMin: undefined })
} else if (min) {
+ if (min > this.availableOptions - 1) {
+ showError(
+ t(
+ 'forms',
+ 'Lower options limit must be smaller than the number of available options',
+ ),
+ )
+ this.onExtraSettingsChange({
+ optionsLimitMin: this.availableOptions - 1 || undefined,
+ })
+ return
+ }
+
if (
this.extraSettings.optionsLimitMax
&& min > this.extraSettings.optionsLimitMax
@@ -413,6 +488,9 @@ export default {
return
}
this.onExtraSettingsChange({ optionsLimitMin: min })
+ if (min > 0) {
+ this.$emit('update:isRequired', true)
+ }
}
},
diff --git a/src/mixins/QuestionMixin.js b/src/mixins/QuestionMixin.js
index fa214f2a9..2cb78dfc8 100644
--- a/src/mixins/QuestionMixin.js
+++ b/src/mixins/QuestionMixin.js
@@ -217,8 +217,16 @@ export default {
return !!this.errorMessage
},
+ hasInfo() {
+ return !!this.infoMessage
+ },
+
errorId() {
- return 'q' + this.index + '_error'
+ return `q${this.index}_error`
+ },
+
+ infoId() {
+ return `q${this.index}_info`
},
/**