Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom collection type: handle add new entity #1470

Closed
maxenceboucas opened this issue Jan 14, 2017 · 6 comments
Closed

Custom collection type: handle add new entity #1470

maxenceboucas opened this issue Jan 14, 2017 · 6 comments

Comments

@maxenceboucas
Copy link

Hi,

I have a working well backend but i would like to know how i can allow to add new element in a collection type

it look like that:
capture d ecran 2017-01-14 a 15 43 42
i would like to be able to add test4 without going to Tag entity editing.
So something like that: https://codepen.io/vineethtr/pen/emaygz

Thanks a lot

@maxenceboucas
Copy link
Author

maxenceboucas commented Jan 19, 2017

I just found that on EasyAdminBundle/Ressources/views/form/bootstrap_3_layout.html.twig

{% block collection_row %}
    {{ block('form_row') }}

    {% if allow_add|default(false) %}
        {% set js_add_item %}
            $(function() {
                if (event.preventDefault) event.preventDefault(); else event.returnValue = false;

                var collection = $('#{{ id }}');
                // Use a counter to avoid having the same index more than once
                var numItems = collection.data('count') || collection.children('div.form-group').length;

                collection.prev('.collection-empty').remove();

                var newItem = collection.attr('data-prototype')
                    .replace(/\>__name__label__\</g, '>' + numItems + '<')
                    .replace(/_{{ name }}___name__/g, '_{{ name }}_' + numItems)
                    .replace(/{{ name }}\]\[__name__\]/g, '{{ name }}][' + numItems + ']')
                ;

                // Increment the counter and store it in the collection
                collection.data('count', ++numItems);

                collection.append(newItem).trigger('easyadmin.collection.item-added');
            });
        {% endset %}

        <div class="text-right field-collection-action">
            <a href="#" onclick="{{ js_add_item|raw }}" class="text-primary">
                <i class="fa fa-plus-square"></i>
                {{ (form|length == 0 ? 'action.add_new_item' : 'action.add_another_item')|trans({}, 'EasyAdminBundle') }}
            </a>
        </div>
    {% endif %}
{% endblock collection_row %}

Some clue ? :)

@AntoscencoVladimir
Copy link

AntoscencoVladimir commented Jan 20, 2017

@maxenceboucas Hi I just try to describe how I implemented tags like you want, except of styles but I think you can do it by yourself.

It will be like this:

screenshot-onk local-2017-01-20-14-09-42

(Also you can see issues about this)

To do it

1.First in my News Entity I have:

<?php

namespace AcmeBundle\Entity\News;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;


/**
 * @ORM\Entity
 * @ORM\Table(name="news")
 */
class News
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", nullable=false)
     */
    private $title;
    
    /**
     * @ORM\ManyToMany(targetEntity="AcmeBundle\Entity\News\NewsTag", cascade={"persist"})
     */
    private $tags;
    

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return mixed
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param mixed $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * -------------------------- Tags ------------------------------
     */

    /**
     * @param NewsTag $tag
     */
    public function addTag(NewsTag $tag)
    {
        $this->tags->add($tag);
    }

    public function removeTag(NewsTag $tag)
    {
        // ...
    }


    /**
     * -------------------------- Tags end-------------------------------
     */
    
    public function getTags()
    {
        return $this->tags;
    }

    

    public function __construct()
    {

        $this->tags = new ArrayCollection();

    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return (string) $this->getTitle();

    }
}

2.Second my Tag Entity:

<?php

namespace AcmeBundle\Entity\News;

use Doctrine\ORM\Mapping as ORM;

/**
 *
 * @ORM\Table(name="news_tags")
 * @ORM\Entity
 */
class NewsTag
{
    /**
     *
     * @var int
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id = null;

    /**
     *
     * @var string
     * @ORM\Column(type="string")
     */
    protected $name;


    protected $news;


    /**
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
    


    public function __construct()
    {

    }

    public function __toString()
    {
        return $this->getName();
    }
}
  1. Customize your admin controller and add action:
 public function createNewsEntityFormBuilder(News $entity, $view)
    {
        $formBuilder = parent::createEntityFormBuilder($entity, $view);

        $formBuilder->remove('tags');

        $formBuilder->add('tags', CollectionType::class, array(
            'allow_add'    => true,
            'allow_delete' => true,
            'by_reference' => false,
            'entry_type' => TagType::class
        ));

        return $formBuilder;
    }
  1. Add Tag Type in AcmeBundle\Form\Type
//AcmeBundle\Form\Type\TagType.php

<?php

namespace AcmeBundle\Form\Type;

use AcmeBundle\Entity\News\NewsTag;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TagType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => NewsTag::class,
        ));
    }
}
  1. In your easy admin config:
easy_admin:
    entities:
        News:
            class: AcmeBundle\Entity\News\News
            label: 'News'
            form:
                title: ""
                fields:
                    #your fields ...
                    - { property: 'tags', type: collection }

@maxenceboucas
Copy link
Author

Thanks a lot for your answer.

I didn't find any issues about creating at the same time new tag and referencing old one in the same Form.

I have this error :
Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "DashboardBundle\Entity\Contact#$tags", got "string" instead.

@AntoscencoVladimir
Copy link

AntoscencoVladimir commented Jan 20, 2017

@maxenceboucas please create exactly like I wrote (don't forget update your schema) and don't add your another's getters setters etc. (you can add it later) it should work in my bundle all works fine

@javiereguiluz
Copy link
Collaborator

I recently closed an issue which was very similar to this one. The problem is that creating a generic way to create new entities on-the-fly while you editing other entity is very complex. I'd like to have that feature as a user ... but it would be a nightmare for us to implement and maintain it. I'm sorry.

@7system7
Copy link

7system7 commented Dec 20, 2017

@maxenceboucas Same here. Impossible to solve this problem in this Bundle... The problem is that in the "add.." method the parameter's type is not the expected type.

UPDATE
I found the solution... It was trivial but I did not see that; in the Type class use configureOptions method instead of setDefaultOptions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants