Skip to content

Commit 30b2983

Browse files
committed
[cookbook][form] Proofreading and tweaking new section on adding elements in a prototype collection
1 parent 8bae5d3 commit 30b2983

File tree

1 file changed

+56
-80
lines changed

1 file changed

+56
-80
lines changed

cookbook/form/form_collections.rst

Lines changed: 56 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -239,56 +239,28 @@ great, your user can't actually add any new todos yet.
239239
Allowing "new" todos with the "prototype"
240240
-----------------------------------------
241241

242-
.. note::
243-
244-
Allowing the user to dynamically add new todos means that we'll need to
245-
use some javascript. Previously we added two tags to our form in the
246-
controller. Now we need to let the user add as many tag forms as he
247-
needs to directly in the browser. This will be done through a bit of
248-
javascripting.
249-
250-
.. tip::
242+
Allowing the user to dynamically add new todos means that we'll need to
243+
use some JavaScript. Previously we added two tags to our form in the controller.
244+
Now we need to let the user add as many tag forms as he needs directly in the browser.
245+
This will be done through a bit of JavaScript.
246+
247+
The first thing we need to do is to tell the form collection know that it will
248+
receive an unknown number of tags. So far we've added two tags and the form
249+
type expects to receive exactly two, otherwise an error will be thrown:
250+
``This form should not contain extra fields``. To make this flexible, we
251+
add the ``allow_add`` option to our collection field::
252+
253+
// ...
251254
252-
If you want to see a working example of how this can be done, you can
253-
check khepin/ProductBundle on github. The basic idea is similar although
254-
it's products and their tags instead of todos.
255-
256-
The first thing we need to do is to let our form collection know that it will
257-
receive an unknown number of tags. So far we added two and the form type
258-
expects to receive two as well otherwise an error will be thrown:
259-
``This form should not contain extra fields``. For this we add the ``'allow_add'``
260-
option to our collection field::
261-
262-
// src/Acme/TaskBundle/Form/Type/TaskType.php
263-
namespace Acme\TaskBundle\Form\Type;
264-
265-
use Symfony\Component\Form\AbstractType;
266-
use Symfony\Component\Form\FormBuilder;
267-
268-
class TaskType extends AbstractType
255+
public function buildForm(FormBuilder $builder, array $options)
269256
{
270-
public function buildForm(FormBuilder $builder, array $options)
271-
{
272-
$builder->add('description');
273-
274-
$builder->add('tags', 'collection', array(
275-
'type' => new TagType(),
276-
'allow_add' => true,
277-
'by_reference' => false,
278-
));
279-
}
257+
$builder->add('description');
280258

281-
public function getDefaultOptions(array $options)
282-
{
283-
return array(
284-
'data_class' => 'Acme\TaskBundle\Entity\Task',
285-
);
286-
}
287-
288-
public function getName()
289-
{
290-
return 'task';
291-
}
259+
$builder->add('tags', 'collection', array(
260+
'type' => new TagType(),
261+
'allow_add' => true,
262+
'by_reference' => false,
263+
));
292264
}
293265

294266
Note that we also added ``'by_reference' => false``. This is because
@@ -297,56 +269,60 @@ a new tag at the time we save the todo and its tags together.
297269

298270
The ``allow_add`` option also does one more thing. It will add a ``data-prototype``
299271
property to the ``div`` containing the tag collection. This property
300-
contains html to add a Tag form element to our page like this::
272+
contains html to add a Tag form element to our page like this:
273+
274+
.. code-block:: html
301275

302276
<div data-prototype="&lt;div&gt;&lt;label class=&quot; required&quot;&gt;$$name$$&lt;/label&gt;&lt;div id=&quot;khepin_productbundle_producttype_tags_$$name$$&quot;&gt;&lt;div&gt;&lt;label for=&quot;khepin_productbundle_producttype_tags_$$name$$_name&quot; class=&quot; required&quot;&gt;Name&lt;/label&gt;&lt;input type=&quot;text&quot; id=&quot;khepin_productbundle_producttype_tags_$$name$$_name&quot; name=&quot;khepin_productbundle_producttype[tags][$$name$$][name]&quot; required=&quot;required&quot; maxlength=&quot;255&quot; /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" id="khepin_productbundle_producttype_tags">
303277
</div>
304278

305279
We will get this property from our javascript and use it to display
306280
new Tag forms. To make things simple, we will embed jQuery in our page
307-
as it allows for more simple cross-browser manipulation of the page.
281+
as it allows for easy cross-browser manipulation of the page.
308282

309283
First let's add a link on the ``new`` form with a class ``add_tag_link``.
310-
Everytime this is clicked by the user, we will add an empty tag for him::
284+
Each time this is clicked by the user, we will add an empty tag for him:
285+
286+
.. code-block:: javascript
311287
312288
$('.record_action').append('<li><a href="#" class="add_tag_link">Add a tag</a></li>');
313289
314-
We also include a template containing the javascript needed to add
315-
the form elements when the link is clicked.
290+
We also include a template containing the javascript needed to add the form
291+
elements when the link is clicked.
316292

317293
.. note:
318294
319-
It is better to separate your javascript in real js files than
295+
It is better to separate your javascript in real JavaScript files than
320296
to write it inside the HTML as we are doing here.
321297
322-
Our script can be as simple as this::
323-
324-
<script>
325-
function addTagForm() {
326-
// Get the div that holds the collection of tags
327-
var collectionHolder = $('#task_tags');
328-
// Get the data-prototype we explained earlier
329-
var prototype = collectionHolder.attr('data-prototype');
330-
// Replace '$$name$$' in the prototype's HTML to
331-
// instead be a number based on the current collection's length.
332-
form = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length);
333-
// Display the form in the page
334-
collectionHolder.append(form);
335-
}
336-
// Add the link to add tags
337-
$('.record_action').append('<li><a href="#" class="add_tag_link">Add a tag</a></li>');
338-
// When the link is clicked we add the field to input another tag
339-
$('a.jslink').click(function(event){
340-
addTagForm();
341-
});
342-
</script>
343-
344-
Now everytime a user clicks the ``Add a tag`` link, a new sub form
345-
will appear on the page. The server side form component is aware
346-
it should not expect any specific size for the ``Tag`` collection.
347-
And all the tags we add while creating the new ``Todo`` will be
348-
saved together with it.
298+
Our script can be as simple as this:
299+
300+
.. code-block:: javascript
301+
302+
function addTagForm() {
303+
// Get the div that holds the collection of tags
304+
var collectionHolder = $('#task_tags');
305+
// Get the data-prototype we explained earlier
306+
var prototype = collectionHolder.attr('data-prototype');
307+
// Replace '$$name$$' in the prototype's HTML to
308+
// instead be a number based on the current collection's length.
309+
form = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length);
310+
// Display the form in the page
311+
collectionHolder.append(form);
312+
}
313+
// Add the link to add tags
314+
$('.record_action').append('<li><a href="#" class="add_tag_link">Add a tag</a></li>');
315+
// When the link is clicked we add the field to input another tag
316+
$('a.jslink').click(function(event){
317+
addTagForm();
318+
});
319+
320+
Now, each time a user clicks the ``Add a tag`` link, a new sub form will
321+
appear on the page. The server side form component is aware it should not
322+
expect any specific size for the ``Tag`` collection. And all the tags we
323+
add while creating the new ``Todo`` will be saved together with it.
349324

325+
For more details, see the :doc:`collection form type reference</reference/forms/types/collection>`.
350326

351327
.. _cookbook-form-collections-remove:
352328

0 commit comments

Comments
 (0)