Fixed problems with non-unique prototype names when using nested collection type, which prevented to create nested entries with mulitple new sub entries.

We now use a unique prototype name for every collection field. This fixes issue #219
This commit is contained in:
Jan Böhmer 2023-02-19 22:39:26 +01:00
parent 1e998fccbb
commit 9d1cd0477a
3 changed files with 25 additions and 2 deletions

View file

@ -27,6 +27,7 @@ export default class extends Controller {
deleteMessage: String,
prototype: String,
rowsToDelete: Number, //How many rows (including the current one) shall be deleted after the current row
fieldPlaceholder: String
}
static targets = ["target"];
@ -65,8 +66,11 @@ export default class extends Controller {
}
const regexString = this.fieldPlaceholderValue || "__name__";
const regex = new RegExp(regexString, "g");
//Apply the index to prototype to create our element to insert
const newElementStr = this.htmlDecode(prototype.replace(/__name__/g, this.generateUID()));
const newElementStr = this.htmlDecode(prototype.replace(regex, this.generateUID()));
//Insert new html after the last child element

View file

@ -52,6 +52,9 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
@ -87,11 +90,25 @@ class CollectionTypeExtension extends AbstractTypeExtension
'reindex_path' => 'id',
]);
//Set a unique prototype name, so that we can use nested collections
$resolver->setDefaults([
'prototype_name' => function (Options $options) {
return '__name_'.uniqid("", false) . '__';
},
]);
$resolver->setAllowedTypes('reindex_enable', 'bool');
$resolver->setAllowedTypes('reindex_prefix', 'string');
$resolver->setAllowedTypes('reindex_path', 'string');
}
public function finishView(FormView $view, FormInterface $form, array $options)
{
parent::finishView($view, $form, $options);
//Add prototype name to view, so that we can pass it to the stimulus controller
$view->vars['prototype_name'] = $options['prototype_name'];
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options): void {

View file

@ -4,11 +4,13 @@
'deleteMessage': deleteMessage|trans,
'prototype': form_widget(form.vars.prototype)|e('html_attr'),
'rowsToDelete': rowsToDelete,
'fieldPlaceholder': form.vars.prototype_name
}) }}
{% else %} {# If add_element is disabled/forbidden, prototype is not available #}
{{ stimulus_controller('elements/collection_type', {
'deleteMessage': deleteMessage|trans,
'rowsToDelete': rowsToDelete
'rowsToDelete': rowsToDelete,
'fieldPlaceholder': form.vars.prototype_name
}) }}
{% endif %}
{% endmacro %}