PluginProbe
The Innovative Form Builder – IvyForms / 0.7
The Innovative Form Builder – IvyForms v0.7
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / public / fields / RadioFormField.vue

RadioFormField.vue in The Innovative Form Builder – IvyForms 0.7, at frontend/src/views/public/fields/RadioFormField.vue

113 lines 3.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template>
2 <div
3 :class="[
4 'ivyforms-field',
5 'ivyforms-field__radio',
6 'ivyforms-field__radio_' + field.id,
7 field.cssClasses,
8 ]"
9 >
10 <IvyFormItem
11 :label="field.hideLabel ? '' : field.label"
12 :required="field.required"
13 :error="error"
14 :prop="field.type + '_' + field.fieldIndex"
15 :show-info="!!field.description"
16 :info-text="String(field.description || '')"
17 :show-info-icon="false"
18 :label-position="field.labelPosition === 'default' ? 'top' : field.labelPosition || 'top'"
19 >
20 <IvyRadioGroup
21 :id="fieldID"
22 v-model="localModelValue"
23 :aria-label="field.label"
24 :disabled="disabled"
25 :readonly="field.readOnly"
26 :required="field.required"
27 direction="vertical"
28 class="ivyforms-field__radio-group ivyforms-flex ivyforms-gap-8"
29 >
30 <IvyRadio
31 v-for="option in radioOptions"
32 :id="option.id"
33 :key="option.id || option.value"
34 :value="option.value"
35 priority="secondary"
36 class="ivyforms-field__radio-option"
37 >
38 {{ option.label }}
39 </IvyRadio>
40 </IvyRadioGroup>
41 </IvyFormItem>
42 </div>
43 </template>
44
45 <script setup lang="ts">
46 import { computed, ref, watch, onMounted, inject } from 'vue'
47 import type { Field } from '@/types/field'
48 interface FieldProps {
49 modelValue: string | number | null | undefined
50 field: Field
51 disabled?: boolean
52 error?: string
53 }
54
55 const props = withDefaults(defineProps<FieldProps>(), {
56 modelValue: '',
57 disabled: false,
58 error: '',
59 })
60
61 const emit = defineEmits(['update:modelValue'])
62
63 const fieldID = `field_${props.field.fieldIndex}`
64 const clearFieldError = inject<(fieldKey: string) => void>('clearFieldError', () => {})
65 const fieldKey = computed(() => props.field.type + '_' + props.field.fieldIndex)
66 const localModelValue = ref(props.modelValue)
67
68 watch(
69 () => props.modelValue,
70 (newVal) => {
71 localModelValue.value = newVal
72 },
73 )
74 watch(localModelValue, (newVal) => {
75 emit('update:modelValue', newVal)
76 clearFieldError(fieldKey.value)
77 })
78 const disabled = computed(() => props.disabled || props.field.readOnly)
79 const error = computed(() => props.error || '')
80 const field = computed(() => props.field)
81
82 // Shuffle options only once on mount
83 const shuffledOptions = ref([])
84 function shuffle<T>(array: T[]): T[] {
85 const arr = array.slice()
86 for (let i = arr.length - 1; i > 0; i--) {
87 const j = Math.floor(Math.random() * (i + 1))
88 ;[arr[i], arr[j]] = [arr[j], arr[i]]
89 }
90 return arr
91 }
92 onMounted(() => {
93 let opts = field.value.fieldOptions || []
94 if (field.value.shuffleOptions) {
95 opts = shuffle(opts)
96 }
97 shuffledOptions.value = opts.map((opt) => ({
98 label: opt.label,
99 value: opt.value,
100 id: opt.id,
101 }))
102 })
103 const radioOptions = computed(() =>
104 shuffledOptions.value.length
105 ? shuffledOptions.value
106 : (field.value.fieldOptions || []).map((opt) => ({
107 label: opt.label,
108 value: opt.value,
109 id: opt.id,
110 })),
111 )
112 </script>
113