Home > Net >  Symfony 6 collection remove item javascript
Symfony 6 collection remove item javascript

Time:11-17

I have a form with a collection in Symfony 6 where it is possible to add and delete items. Adding and removing a collection works. The problem is only if an error is rendered in the form ($form->addError(new FormError('Some Error'));). At that point, the link to remove the collection will be lost, but the items will still be rendered. What is needed so that the "remove" link does not disappear?

const addTagLink = document.createElement('a')
addTagLink.classList.add('add')
addTagLink.href = '#'
addTagLink.innerText = 'Add'
addTagLink.dataset.collectionHolderClass = 'items'

const collectionHolder = document.querySelector('ul.items')
collectionHolder.appendChild(addTagLink)

const addFormToCollection = (e) => {
  const collectionHolder = document.querySelector('.'   e.currentTarget.dataset.collectionHolderClass);

  const item = document.createElement('li');

  item.innerHTML = collectionHolder
    .dataset
    .prototype
    .replace(
      /__name__/g,
      collectionHolder.dataset.index
    );

  collectionHolder.appendChild(item);
  collectionHolder.dataset.index  ;

  const removeLink = document.createElement('a');
  removeLink.href = '#';
  removeLink.innerText = 'Remove';
  removeLink.classList.add('remove');

  item.appendChild(removeLink);

  removeLink.addEventListener('click', (e) => {
    e.preventDefault();
    item.remove();
  })
}

addTagLink.addEventListener("click", addFormToCollection)
<form name="expedition" method="post">
  <div>
    <ul  data-index="0" data-prototype="&lt;div&#x20;id&#x3D;&quot;expedition_items___name__&quot;&gt;&lt;div&gt;&lt;label&#x20;class&#x3D;&quot;block&#x20;text-sm&#x20;font-medium&#x20;text-gray-700&#x20;required&quot;&#x20;for&#x3D;&quot;expedition_items___name___quantity&quot;&gt;Quantity&lt;&#x2F;label&gt;&lt;input&#x20;type&#x3D;&quot;text&quot;&#x20;id&#x3D;&quot;expedition_items___name___quantity&quot;&#x20;name&#x3D;&quot;expedition&#x5B;items&#x5D;&#x5B;__name__&#x5D;&#x5B;quantity&#x5D;&quot;&#x20;required&#x3D;&quot;required&quot;&#x20;class&#x3D;&quot;block&#x20;w-full&#x20;shadow-sm&#x20;border-gray-300&#x20;rounded-md&#x20;border&#x20;p-2&#x20;mt-1&#x20;mb-2&quot;&#x20;inputmode&#x3D;&quot;decimal&quot;&#x20;&#x2F;&gt;&lt;&#x2F;div&gt;&lt;div&gt;&lt;label&#x20;class&#x3D;&quot;block&#x20;text-sm&#x20;font-medium&#x20;text-gray-700&#x20;required&quot;&#x20;for&#x3D;&quot;expedition_items___name___product&quot;&gt;Product&lt;&#x2F;label&gt;&lt;select&#x20;id&#x3D;&quot;expedition_items___name___product&quot;&#x20;name&#x3D;&quot;expedition&#x5B;items&#x5D;&#x5B;__name__&#x5D;&#x5B;product&#x5D;&quot;&#x20;required&#x3D;&quot;required&quot;&#x20;class&#x3D;&quot;block&#x20;w-full&#x20;shadow-sm&#x20;border-gray-300&#x20;rounded-md&#x20;border&#x20;p-2&#x20;mt-1&#x20;mb-2&quot;&gt;&lt;option&#x20;value&#x3D;&quot;&quot;&#x20;selected&#x3D;&quot;selected&quot;&gt;Choose&#x20;a&#x20;product&lt;&#x2F;option&gt;&lt;option&#x20;value&#x3D;&quot;2&quot;&gt;Product&#x20;1&lt;&#x2F;option&gt;&lt;option&#x20;value&#x3D;&quot;3&quot;&gt;Product&#x20;2&lt;&#x2F;option&gt;&lt;&#x2F;select&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;">
    </ul>
  </div>
  <button type="submit">Save</button>
</form>

twig

{{ form_start(form) }}
{% if form_errors(form) %}
<div >{{ form_errors(form) }}</div>
{% endif %}
<div>
    <ul 
        data-index="{{ form.items|length > 0 ? form.items|last.vars.name   1 : 0 }}"
        data-prototype="{{ form_widget(form.items.vars.prototype)|e('html_attr') }}">
                <li >
                    {{ form_label(form.items) }}
                    {{ form_widget(form.items) }}
                    {{ form_errors(form.items) }}
               <li>
    </ul>
</div>

<button type="submit" >{{ 'Save'|trans }}</button>

{{ form_end(form)}}

CodePudding user response:

Render your items in a loop to give each item its own <li>:

    <ul 
        data-index="{{ form.items|length > 0 ? form.items|last.vars.name   1 : 0 }}"
        data-prototype="{{ form_widget(form.items.vars.prototype)|e('html_attr') }}">
        {% for itemForm in form.items %}
            <li >
                {{ form_label(itemForm) }}
                {{ form_widget(itemForm) }}
                {{ form_errors(itemForm) }}
            </li>
        {% endfor %}
    </ul>

Then create a JavaScript function that adds a remove link to a given item:

    const addItemFormDeleteLink = (item) => {
        const removeLink = document.createElement('a');
        removeLink.href = '#';
        removeLink.innerText = 'Remove';
        removeLink.classList.add('remove');

        item.appendChild(removeLink);

        removeLink.addEventListener('click', (e) => {
            e.preventDefault();
            item.remove();
        })
    }

And use this to add the remove link to the existing items on the page:

    document
        .querySelectorAll('ul.items li')
        .forEach((tag) => {
            addItemFormDeleteLink(tag)
        })

And in addFormToCollection:

    const addFormToCollection = (e) => {
        const collectionHolder = document.querySelector('.'   e.currentTarget.dataset.collectionHolderClass);

        const item = document.createElement('li');

        item.innerHTML = collectionHolder
            .dataset
            .prototype
            .replace(
            /__name__/g,
            collectionHolder.dataset.index
            );

        collectionHolder.appendChild(item);
        collectionHolder.dataset.index  ;

        // add a delete link to the new form
        addItemFormDeleteLink(item);
    }

See also: https://symfony.com/doc/current/form/form_collections.html#allowing-tags-to-be-removed

  • Related