useCwaFormRepeated
useCwaFormRepeated wraps two useCwaFormInput instances for a Symfony RepeatedType field. Each side validates with the sibling's current value so the API can check that both entries match.
const { first, second } = useCwaFormRepeated(iri, 'form_name[fieldName]')
Parameters
| Parameter | Type | Description |
|---|---|---|
iri | Ref<string | undefined> | IRI of the Form component resource |
fullName | string | full_name of the RepeatedType field (e.g. registration[plainPassword]) |
Return value
Returns { first, second } — each has the same shape as a useCwaFormInput return value:
| Property | Type | Description |
|---|---|---|
value | Ref<string> | Field value; bind with v-model="field.value.value" |
vars | ComputedRef | Field vars from the API (label, required, etc.) |
errors | ComputedRef<string[]> | Field-level errors (see pair-mismatch note below) |
valid | ComputedRef<null | boolean> | null until both sub-fields have a value; then reads the parent RepeatedType node's validity |
displayErrors | ComputedRef<boolean> | Gated on both fields having been blurred — see below |
onBlur | () => void | Call on the input's blur event |
onInput | () => void | Debounced; triggers cross-field validation |
validate | (extraData?) => Promise<void> | Explicit validate — PATCHes to the form's /submit endpoint |
Error display gate
displayErrors is false until both first and second have been blurred at least once — or the form has been submitted and failed, or the pair was previously valid and has since become invalid. This stops a mismatch error appearing on the second field the moment the user leaves the first, without hiding errors after a failed submit. It is also suppressed while a validation request is in flight.
Cross-field validation
onInput and onBlur are overridden to pass the sibling's current value as extraData when it is non-empty. This lets the API validate that both entries match without requiring a full form submit. If the sibling field is still empty, no extraData is sent.
Pair-mismatch errors
Symfony attaches pair-mismatch errors to [first]. When the mismatch is detected after the user typed in the second field, the composable redirects those errors to second.errors so the message appears next to the field the user most recently edited.
Example
<script setup lang="ts">
const props = defineProps<{ iri: string }>()
const iriRef = toRef(props, 'iri')
const password = useCwaFormRepeated(iriRef, 'registration[plainPassword]')
</script>
<template>
<UFormField
:label="password.first.vars.value?.label || 'New Password'"
:error="password.first.displayErrors.value ? password.first.errors.value[0] : undefined"
>
<UInput
v-model="password.first.value.value"
type="password"
autocomplete="new-password"
@blur="password.first.onBlur"
@input="password.first.onInput"
/>
</UFormField>
<UFormField
:label="password.second.vars.value?.label || 'Confirm Password'"
:error="password.second.displayErrors.value ? password.second.errors.value[0] : undefined"
>
<UInput
v-model="password.second.value.value"
type="password"
autocomplete="new-password"
@blur="password.second.onBlur"
@input="password.second.onInput"
/>
</UFormField>
</template>
Notes
- Internally maps to
{fullName}[first]and{fullName}[second]— these match Symfony's RepeatedType child names - Each side registers its own
full_namein the form store viauseCwaFormInput—useCwaForm.unregisteredFieldErrorswill not include them - See the Forms guide for full context