CWA 2.0 is in alpha: try it, build with it, give feedback. APIs can still change between releases; see Releases.
Form
useCwaFormCollection
Manage a Symfony CollectionType field — dynamically add and remove entries at runtime.
useCwaFormCollection manages a Symfony CollectionType field. It clones the prototype from the API response each time addEntry() is called, assigns a monotonic index, and tracks the list of active entry full_name strings. Child components then call useCwaFormInput for each sub-field; their lifecycle hooks handle registration/unregistration automatically.
const { entries, addEntry, removeEntry, vars } = useCwaFormCollection(iri, 'form_name[fieldName]')
Signature
useCwaFormCollection(iri: Ref<string | undefined>, collectionFullName: string)
Parameters
| Parameter | Type | Description |
|---|---|---|
iri | Ref<string | undefined> | IRI of the Form component resource |
collectionFullName | string | full_name of the CollectionType field (e.g. registration[tags]) |
Return Values
| Property | Type | Description |
|---|---|---|
entries | ComputedRef<string[]> | Ordered list of active entry full_name strings. Starts with the entries already in the form view, so an edit form lists its existing items |
addEntry | () => void | Clone the prototype and append a new entry |
removeEntry | (fullName: string) => void | Remove an entry by its full_name |
vars | ComputedRef | Collection field vars from the API (label, allow_add, allow_delete, errors, etc.) |
How It Works
addEntry()deep-clones the collection field'sprototype. The prototype is a sibling ofvarson the form view ($cwa.forms.getForm(iri)[collectionFullName].prototype), not one of its vars.- It replaces every
__name__placeholder with a monotonic counter, recursively through nested children. - Symfony's
__name__label__sentinel label is dropped. - It then pushes the resolved
full_nameontoentries. - Entries already in the form view are read when it loads and can be removed like added ones. New entries take the next free index after them
- Indices are never reused after removal, so Vue
v-forkeys remain stable - The prototype is never mutated
- Child components must call
useCwaFormInput(iriRef, entryFullName)(oruseCwaFormInput(iriRef, \${entryFullName}subField`)for compound types) — each child registers its field value with the form store during setup (immediately, not on mount) and clears it inonBeforeUnmount`
Example
Simple Collection (TextType Entries)
Working with Forms → CollectionType has a full parent and entry component with Nuxt UI, including a validation icon on each entry.
Compound Collection (Sub-Fields per Entry)
For a CollectionType where each entry is a compound type (e.g. a ChildType with name and age sub-fields), the child component calls useCwaFormInput for each sub-field:
<!-- ChildEntry.vue -->
<script setup lang="ts">
const props = defineProps<{ iri: string | undefined, entryFullName: string }>()
defineEmits<{ remove: [] }>()
const iriRef = toRef(props, 'iri')
const name = useCwaFormInput(iriRef, `${props.entryFullName}[name]`)
const age = useCwaFormInput(iriRef, `${props.entryFullName}[age]`)
</script>
Notes
- Use
vars.value?.allow_add/vars.value?.allow_delete(from the API response) to conditionally show add/remove controls - Collection-level errors (e.g. min/max count violations) are in
vars.value?.errors— render them separately from individual entry errors - Entries removed via
removeEntry()are immediately dropped fromentries; the child component unmounts anduseCwaFormInputunregisters the field values, so they are excluded from the nextsubmit()payload automatically - See the Forms guide for full field-type examples