If you render complex nested forms without the general form(form) helper and
instead render each field manually, make sure the DOM still contains elements
for every relevant Symfony form node.
For example, a task form with a tags collection has a structure similar to:
task:
# ...
tags:
collection:
tag_1:
name
tag_2:
nameDefault rendering creates a collection holder:
<form name="form_task" method="post" action="" novalidate="novalidate">
<div id="form_task">
<div>
<label class="required">Tags</label>
<div id="form_task_tags" data-prototype="...">
<div>
<label class="required">0</label>
<div id="form_task_tags_0">
<div>
<label for="form_task_tags_0_name" class="required">Name</label>
<input type="text" id="form_task_tags_0_name" name="form_task[tags][0][name]" required="required">
</div>
</div>
</div>
<div>
<label class="required">1</label>
<div id="form_task_tags_1">
<div>
<label for="form_task_tags_1_name" class="required">Name</label>
<input type="text" id="form_task_tags_1_name" name="form_task[tags][1][name]" required="required">
</div>
</div>
</div>
</div>
</div>
</div>
</form>The id="form_task_tags" holder is important: it represents the direct form
child named tags, stores the collection prototype, and can carry validation
metadata for the collection field itself.
If you manually render only the nested name fields, you can lose validation
metadata:
{{ form_start(form) }}
{{ form_row(form.description) }}
<h3>Tags</h3>
<ul class="tags">
{% for tag in form.tags %}
<li>{{ form_row(tag.name) }}</li>
{% endfor %}
</ul>
{{ form_end(form) }}Keep the collection and child IDs in the DOM:
{{ form_start(form) }}
{{ form_row(form.description) }}
<h3>Tags</h3>
<ul class="tags" id="{{ form.tags.vars.id }}">
{% for tag in form.tags %}
<li id="{{ tag.vars.id }}">
{{ form_row(tag.name) }}
</li>
{% endfor %}
</ul>
{{ form_end(form) }}