Installation:
composer require arkounay/ux-collection
npm install --force && npm run watch
Ensure StimulusBundle is configured in your Symfony app.
Basic Usage:
Replace CollectionType with UxCollectionType in your form builder:
use Arkounay\Bundle\UxCollectionBundle\Form\UxCollectionType;
$builder->add('items', UxCollectionType::class, [
'entry_type' => ItemType::class,
'allow_add' => true,
'allow_delete' => true,
]);
First Use Case: Create a dynamic form for a product variant collection (e.g., SKUs, colors, sizes) where users can add/remove variants via a clean UI.
Dynamic Collections:
Use allow_add/allow_delete for CRUD operations on form entries (e.g., multi-step forms, nested configurations).
'allow_add' => true,
'allow_delete' => true,
'min' => 1, // Enforce minimum items
'max' => 5, // Limit maximum items
Reordering Items: Enable drag-and-drop for sortable lists (e.g., priority queues, step-by-step workflows):
'allow_drag_and_drop' => true,
'drag_and_drop_filter' => 'input,textarea,button', // Exclude specific elements
Nested Collections:
Configure child collections with unique prototype_name to avoid conflicts:
'entry_type' => NestedItemType::class,
'prototype_name' => '__nested_item__', // Custom prototype name
Custom Styling: Override default classes via form options:
'add_class' => 'btn btn-primary',
'add_wrapper_class' => 'mb-4',
Event Listening: Extend functionality with Stimulus controllers (e.g., real-time validation, analytics):
'attr' => [
'data-controller' => 'custom-collection',
'data-action' => 'ux-collection:change->parent#updateTotal'
],
StimulusBundle and WebpackEncore.configureCrud():
->addFormTheme('@ArkounayUxCollection/ux_collection_form_theme.html.twig')
assets/controllers.json:
"@arkounay/ux-collection": { "collection": { "enabled": true } }
File Inputs:
Disable sorting (allow_drag_and_drop: false) if using VichUploaderBundle to avoid form name conflicts.
Alternatively, use position_selector to manually manage positions:
'position_selector' => '.position-input',
Nested Collections:
prototype_name (e.g., __parent__[__child__]).Bootstrap 5:
Disable standalone CSS in controllers.json to avoid conflicts:
"@arkounay/ux-collection/src/style-when-not-using-bootstrap-5.css": false
Event Handling:
ux-collection:change for real-time updates (e.g., cart totals).assets/controllers.json:
"custom-collection": { "path": "path/to/controller.js" }
Deprecations:
spaceless filter is deprecated (v4.0.2+). Update templates if using custom themes._onAdd(event) { console.log('Added item:', event.detail); }
@ArkounayUxCollection/ux_collection.html.twig for custom HTML..arkounay-ux-collection classes.Custom Controllers: Extend default behavior via Stimulus (e.g., auto-focus new items):
connect() {
this.element.addEventListener('ux-collection:add', (e) => {
e.detail.target.querySelector('input').focus();
});
}
Validation:
Use ux-collection:change to trigger custom validation (e.g., duplicate checks):
'attr' => ['data-action' => 'ux-collection:change->validator#checkDuplicates']
Localization:
Override translations in your bundle’s Resources/translations/ (e.g., messages.en.yaml):
arkounay_ux_collection:
add: "Ajouter un élément" # French override
Alternative Collection Types:
UxHorizontalCollectionType for left-to-right layouts.UxTabbedCollectionType (Bootstrap 5 required; customize CSS via tabbed-style.css).allow_drag_and_drop for large collections (>50 items) to reduce JS overhead.aria-live regions for dynamic updates:
<div aria-live="polite">{{ form_row(form) }}</div>
FormTestCase to verify collection behavior:
$form->submit(['items' => [['name' => 'Item 1'], ['name' => 'Item 2']]]);
$this->assertEquals(2, count($form->getData()['items']));
How can I help you explore Laravel packages today?