Skip to content

Instantly share code, notes, and snippets.

@bjo3rnf
Last active January 24, 2026 08:50
Show Gist options
  • Select an option

  • Save bjo3rnf/85e8490b98955cb6016f44445d9843fb to your computer and use it in GitHub Desktop.

Select an option

Save bjo3rnf/85e8490b98955cb6016f44445d9843fb to your computer and use it in GitHub Desktop.
Stimulus.js controller for Symfony collection form type with configurable item limit
{% macro collection_item(form) %}
<div data-form-collection-target="field">
{{ form_widget(form) }}
<button type="button"
data-action="form-collection#removeItem">
remove
</button>
</div>
{% endmacro %}
{% import _self as formMacros %}
{{ form_start(form) }}
<div data-controller="form-collection"
data-form-collection-max-items-value="10">
<div data-form-collection-target="fields">
{% do form.collectionField.setRendered %}
{% for field in form.collectionField %}
{{ formMacros.collection_item(field) }}
{% endfor %}
</div>
<button type="button"
data-action="form-collection#addItem"
data-form-collection-target="addButton">
add
</button>
<template data-form-collection-target="prototype">
{{ formMacros.collection_item(form.collectionField.vars.prototype) }}
</template>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
import { Controller } from 'stimulus'
export default class extends Controller {
static targets = [ 'fields', 'field', 'prototype', 'addButton' ]
static values = {
prototype: String,
maxItems: Number,
itemsCount: Number,
}
connect() {
this.index = this.itemsCountValue = this.fieldTargets.length
}
addItem() {
let prototype = this.prototypeTarget.innerHTML
const newField = prototype.replace(/__name__/g, this.index)
this.fieldsTarget.insertAdjacentHTML('beforeend', newField)
this.index++
this.itemsCountValue++
}
removeItem(event) {
this.fieldTargets.forEach(element => {
if (element.contains(event.target)) {
element.remove()
this.itemsCountValue--
}
})
}
itemsCountValueChanged() {
if (false === this.hasAddButtonTarget || 0 === this.maxItemsValue) {
return
}
const maxItemsReached = this.itemsCountValue >= this.maxItemsValue
this.addButtonTarget.classList.toggle('hidden', maxItemsReached)
}
}
@dbu
Copy link

dbu commented Jul 26, 2025

ah, it is pretty recent, was added in symfony 7.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment