Here's the plan: I want to add a button called "Add New Scientist", and when the
user clicks it, it will render a new blank, embedded GenusScientist form. After
the user fills in those fields and saves, we will insert a new record into the genus_scientist
table.

The allow_add Option

Let's start with the front end first. Open GenusFormType. After the allow_delete
option, put a new one: allow_add set to true:

First, under the "Allowing New" section, find the template and copy the data-prototype
attribute code. Open our form template, and add this to the wrapper div.
Update the variable to genusForm.genusScientists.vars.prototype:

That will count the number of embedded forms that the form has right now.

Don't touch anything else: let's refresh the page to see what this looks like...
because it's kind of crazy.

Wait, oh damn, I have three "Add New Scientist" links. Make sure your link is
outside of the for loop. This link is great... but not so great that I want
it three times. Oh, and fix the icon class too - get it together Ryan!

Checking out the prototype: __name__

View the HTML source and search for wrapper to find our js-genus-scientist-wrapper
element. That big mess of characters is the prototype. Yep, it looks crazy.
This is a blank version of one of these embedded forms... after being escaped with
HTML entities so that it can safely live in an attribute. This is great, because
we can read this in JavaScript when the user clicks "Add New Scientist".

Oh, but check out this __name__ string: it shows up in a bunch of places inside
the prototype. Scroll down a little to the embedded GenusScientist forms. If
you look closely, you'll see that the fields in each of these forms have a different
index number. The first is index zero, and it appears in a few places, like the
name and id attributes. The next set of fields use one and then two.

When Symfony renders the prototype, instead of hard coding a number there - like
zero, one or two - it uses __name__. It then expects us - in JavaScript - to
change that to a unique index number, like three.

The Prototype JavaScript

Let's do it! Back on the Symfony documentation page: a lot of the JavaScript we
need lives here. Find the addTagForm() function and copy the inside of it. Back
in edit.html.twig, paste this inside our click function.

And let's make some changes. First, update $collectionHolder to $wrapper: that's
the element that has the data-prototype attribute. We also read the data-index
attribute... which is important because it tells us what number to use for the
index. This is used to replace__name__ with that number. And then, each time
we add another form, this index goes up by one.

Finally, at the very bottom: put this new sub-form onto the page: $(this) -
which is the "Add another Scientist" link, $(this).before(newForm):

52 lines app/Resources/views/admin/genus/edit.html.twig

... lines 1 - 2

{% block javascripts %}

{{ parent() }}

<script>

jQuery(document).ready(function() {

var $wrapper = $('.js-genus-scientist-wrapper');

... lines 9 - 17

$wrapper.on('click', '.js-genus-scientist-add', function(e) {

e.preventDefault();

// Get the data-prototype explained earlier

var prototype = $wrapper.data('prototype');

// get the new index

var index = $wrapper.data('index');

// Replace '__name__' in the prototype's HTML to

// instead be a number based on how many items we have

var newForm = prototype.replace(/__name__/g, index);

// increase the index with one for the next item

$wrapper.data('index', index + 1);

// Display the form in the page before the "new" link

$(this).before(newForm);

});

});

</script>

{% endblock %}

... lines 40 - 52

I think we are ready! Find your browser and refresh! Hold your breath: click
"Add Another Scientist". It works! Well, the styling isn't quite right... but hey,
this is a victory! And yea, we'll fix the styling later.

Add one new scientist, and hit save. Ah! It blows up! Obviously, we have a little
bit more work to do.

Leave a comment!

2017-11-10Victor Bocharsky

Ah, anyway I'm glad you got it working, well done!

Cheers!

2017-11-09Kjell K.

Cheers, I discovered that. I did not double it up. But the java scripts were put inline in the base.html. Ended up moving the js snipps to separate files and including, and that solved the problem. Finally got it working, after too many hours of banging my head against the wall. And worse still, I still don't know why it solved the problem. I must admit I did not follow the complete course, only stole the parts I needed. But thank you very much for your prompt reply, it is much appreciated!

2017-11-09Victor Bocharsky

Hi Kjell,

Hm, probably you just made a misprint somewhere or doubled some html/js code, could you double check and compare your code with ours one more time? Press "Download" button in the right top corner of any video page of this course, then click "Course Code". In finish/ folder you'll find the finish code for this tutorial. It's difficult to say more about what could be a problem based on your question, sorry.

Cheers

2017-11-08Kjell K.

Hi,

Could someone think of any reason why the prototype object contains double the number of items I put in it? Whenever I click the add collection button, two sets are inserted.

Themes are great when you want/need forms with the same layout, it will reduce you a lot of the work, and even if you need different layouts, because you can create multiple Form themes, and then just choose the one you need

Have a nice day!

2017-07-27Ahmed Bhs

Happy to find such an amazing Tuto talking about CollectionType, as usual <3Have somes question wish I got responses:As I see you worked with macros, this has two benefits first rending the form many times via the macro block, second, customizing the collection prototype.But there's other trick, can do the same job, I saw some article such http://symfony.com/doc/mast... talking about, how to override the prototype using twig themes,