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> | false until both fields have been blurred at least once (see below) |
onBlur | () => void | Call on the input's blur event |
onInput | () => void | Debounced; triggers cross-field validation |
validate | (extraData?) => Promise<void> | Explicit validate (PATCH forms only) |
Error display gate
displayErrors is false until both first and second have each been blurred at least once. This prevents surfacing a mismatch error on the second field the moment the user focuses the first — both fields must be visited before any pair-level error is shown.
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