ninsuo / symfony-collection

[NOT MAINTAINED] A jQuery plugin that manages adding, deleting and moving elements from a Symfony form collection
https://symfony-collection.fuz.org/
MIT License
444 stars 88 forks source link

Problem with collection validation labels #143

Open TheLaska opened 5 years ago

TheLaska commented 5 years ago

Hello, first of all i really enjoy the plugin and appreciate the huge amount of work that all of you have done :)

I stumbled upon the following issue, when having a form with a collection, i always add new elements at the end of the collection and have the CollectionType option 'by_reference' set to false, so the adders and removers are automatically called when i flush the object after submitting the form.

Lets say we added 2 elements to the collection:

collection[0]element[0] collection[0]element[1]

after we remove the last one and then add it again, in the form view we have:

collection[0]element[0] collection[0]element[2]

This behaviour is caused by the fact, that the offset value is stored in the collection.data('collection-offset') and in the method doAdd the value of the offset is always incremented by 1 when adding a new element.

After submitting the form, validation is called, in the case the field entries are invalid, the validator points to elements:

collection[0]element[0] collection[0]element[1]

but element having the index = 1 does not exist in the form view, this fact causes the error labels to appear at the top of the form (or at the bottom if we have error_bubbling=false).

I could enforce the proper behaviour by setting in the form class by_reference=true, but then i had to manuallly manage the relatinonship by calling the adder and settting the collection parent object on each member of the collection - this would cause a hudge problem, because the project i am working on is quite large and would require a great amount of refactoring.

So i figured out a solution, i added a bit of code to the plugin method doAdd:

if (settings.add_at_the_end === true) { var lastElementId = null; var elementsLength = elements.length; if (elementsLength === undefined) { lastElementId = 0; } else { lastElementId = elementsLength; } collection.data('collection-offset', lastElementId); }

var freeIndex = collection.data('collection-offset');

This ensures that if we always add elements to the end of the collection, the added element has index greater by one than the last element. This does not collide with the rest of the plugin (because removing or copying or even moving elements around always reindexes them properly) and ensures proper display of the validation error labels.

After testing this was the only solution to ensure, that the keys from the view and the actual form object are consistent and removes the need to write a custom form extension class that reindexes the keys before the submit action happens. Moreover, we add elements to the end of the collection anyway :)

If there is another option, or I have a wrong understanding how the plugin works, please correct me :)

If you like this feature and you think it is logically consistent and correct, i would gladly make a pull request or a fork.

Cheers