PluginProbe
The Innovative Form Builder – IvyForms / 1.1
The Innovative Form Builder – IvyForms v1.1
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 1.1, at frontend/src/views/public/fields/RadioFormField.vue

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