symfony-collection
symfony-collection copied to clipboard
Problem with removing and moving buttons
Hi there!
This plugin is great, I'm really grateful for sharing it, good job! Now managing collections is pretty easy.
But I've got 2 problems: 1st: I can add new element to collection, I just click '+", enter the data, and then click submit/save and it's done. But how can I remove the element? Ok, when I click '-' the element disappear, I need to submit the form, but I can't. The submit button is deleted too. Each form of collection has own submit button, but in the examples there's only one button to submit. How can I handle with my case? I enclose screenshot of my form.
Screenshot: here
2nd: When I set allow_up: false and allow_down: false all my controls have been gone. I can't even add the element. Now I'm using custom theme. What am I doing wrong?
I'd be grateful for any help or advice. Thank you in advance.
Best regards
Hello!
Can you please share your form theme and the way you display it?
Difficult to reproduce without any code :-)
Thanks,
A
Hi!
Thank you very much for quick response. Before sharing my code, I need to provide more information. So - I have user entity and user form. In user's entity there are few entities that are using oneToMany relationships - e.g. Language. In user's form I embed forms from these entities - e.g. LanguageType.
Displaying form:
{% extends 'base.html.twig' %}
{% block content %}
<main class="registration registration-second">
<div class="container">
<h1>Edytuj profil</h1>
{% form_theme form 'jquery.collection.html.twig' %}
{{ form_start(form, {'attr':{'novalidate':'novalidate', 'class':'registration-form form-edit' }}) }}
<div class="boxes">
<div class="roll-down">
<a class="toggle-menu"><span class="">Podstawowe informacje</span></a>
</div>
<div class="registration-form-wrapper opened">
<div class="form-input form-text-field {% if not form.firstname.vars.valid %}has-error{% endif %}">
{{ form_errors(form.firstname) }}
<span>{{ form_label(form.firstname) }}</span>
{{ form_widget(form.firstname) }}
<span>wymagane</span>
</div>
<div class="form-input form-text-field {% if not form.lastname.vars.valid %}has-error{% endif %}">
{{ form_errors(form.lastname) }}
<span>{{ form_label(form.lastname) }}</span>
{{ form_widget(form.lastname) }}
<span>wymagane</span>
</div>
<div class="form-input form-text-field {% if not form.birthday.vars.valid %}has-error{% endif %}">
{{ form_errors(form.birthday) }}
<span>{{ form_label(form.birthday) }}</span>
{{ form_widget(form.birthday) }}
<span>wymagane</span>
</div>
<div class="form-input form-text-field {% if not form.residence.vars.valid %}has-error{% endif %}">
{{ form_errors(form.residence) }}
<span>{{ form_label(form.residence) }}</span>
{{ form_widget(form.residence) }}
<span>wymagane</span>
</div>
<div class="text-field"><span>Twój adres e-mail służy do zalogowania</span></div>
<div class="form-toggle">
{{ form_row(form.save) }}
</div>
</div>
</div>
{{ form_end(form) }}
</div>
</main>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
$('.my-selector').collection();
$('.my-selector2').collection();
$('.my-selector3').collection();
$('.my-selector4').collection();
</script>
{% endblock %}
My form - UserType.php:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Doctrine\ORM\EntityRepository;
use AppBundle\Form\EducationType;
use AppBundle\Form\CourseType;
use AppBundle\Form\ExperienceType;
use AppBundle\Form\LanguageType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class EmployeeAccountType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//var_dump($options['user']); exit;
$builder
->add('firstname', TextType::class, array(
'label' => 'Imię',
'attr' => array(
'maxlength' => 70,
'minlength' => 1,
'placeholder' => 'Twoje imię'
)
))
->add('lastname', TextType::class, array(
'label' => 'Nazwisko',
'attr' => array(
'maxlength' => 70,
'minlength' => 1,
'placeholder' => 'Twoje nazwisko'
)
))
->add('birthday', TextType::class, array(
'label' => 'Data urodzenia: ',
'attr' => array(
'maxlength' => 70,
'minlength' => 1,
'placeholder' => 'Twoja data urodzenia'
)
))
->add('residence', TextType::class, array(
'label' => 'Miejsce zamieszkania: ',
'attr' => array(
'maxlength' => 70,
'minlength' => 1,
'placeholder' => 'Twoje miejsce zamieszkania'
)
))
->add('educations', CollectionType::class, array(
'entry_type' => EducationType::class,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype' => true,
'by_reference' => false,
'attr' => array(
'class' => 'my-selector',
),
))
->add('courses', CollectionType::class, array(
'entry_type' => CourseType::class,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype' => true,
'by_reference' => false,
'attr' => array(
'class' => 'my-selector2',
),
))
->add('experiences', CollectionType::class, array(
'entry_type' => ExperienceType::class,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype' => true,
'by_reference' => false,
'attr' => array(
'class' => 'my-selector3',
),
))
->add('languages', CollectionType::class, array(
'entry_type' => LanguageType::class,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype' => true,
'by_reference' => false,
'attr' => array(
'class' => 'my-selector4',
),
))
->add('save', SubmitType::class, array(
'label' => 'Zapisz i zaaktualizuj informacje',
'attr' => array('class' => 'button button-primary button-md')
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User',
'user' => null
));
}
}
User entity - User.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Timestampable\Traits\Timestampable;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use AppBundle\Entity\Company;
/**
* User
*
* @ORM\Table(name="users")
* @ORM\Entity
* @UniqueEntity("email",message="Taki adres e-mail jest już zarejestrowany w bazie. ")
*
*/
class User implements AdvancedUserInterface, \Serializable
{
use TimestampableEntity;
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=80, unique=true)
* @Assert\NotBlank(groups={"employer_registration", "employee_registration"}, message="To pole jest wymagane. ")
* @Assert\Email(
* message = "Wprowadzony adres e-mail: {{ value }} nie jest poprawny.",
* checkMX = true
* )
*
*/
private $email;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(groups={"employer_registration", "employee_registration", "change_password"}, message="To pole jest wymagane. ")
*/
private $password;
/**
* @ORM\Column(name="account_non_expired", type="boolean")
*/
private $accountNonExpired = true;
/**
* @ORM\Column(name="account_non_locked", type="boolean")
*/
private $accountNonLocked = true;
/**
* @ORM\Column(name="credentials_non_expired", type="boolean")
*/
private $credentialsNonExpired = true;
/**
* @ORM\Column(type="boolean")
*/
private $enabled = true;
/**
* @ORM\Column(name = "action_token", type="string", length=32, nullable=true)
*/
private $actionToken;
/**
* @ORM\Column(name="roles", type="array")
*/
protected $roles;
/**
* @ORM\Column(name="terms", type="boolean")
* @Assert\NotBlank(groups={"employer_registration", "employee_registration"}, message="Akceptacja regulaminu jest wymagana. ")
*/
private $terms = false;
/**
* @ORM\Column(name="giodo_contact", type="boolean")
*/
private $giodoContact = false;
/**
* @ORM\Column(name="giodo_information", type="boolean")
*/
private $giodoInformation = false;
/**
* @ORM\Column(type="text", length=500, nullable=true)
*/
private $description;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank(groups={"employee_registration", "employer_profile_edit"}, message="To pole jest wymagane. ")
*/
private $firstname;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank(groups={"employee_registration", "employer_profile_edit"}, message="To pole jest wymagane. ")
*/
private $lastname;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank(groups={"employer_profile_edit"}, message="To pole jest wymagane. ")
*/
private $birthday;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\NotBlank(groups={"employer_profile_edit"}, message="To pole jest wymagane. ")
*/
private $residence;
/**
* @Assert\Type(type="AppBundle\Entity\Company")
* @Assert\Valid()
* @ORM\OneToOne(targetEntity="Company")
*/
protected $company;
/**
* @Assert\Valid()
* @ORM\OneToMany(targetEntity="Experience", mappedBy="user", cascade={"persist", "remove"})
*/
private $experiences;
/**
* @Assert\Valid()
* @ORM\OneToMany(targetEntity="Education", mappedBy="user", cascade={"persist", "remove"})
*/
private $educations;
/**
* @Assert\Valid()
* @ORM\OneToMany(targetEntity="Language", mappedBy="user", cascade={"persist", "remove"})
*/
private $languages;
/**
* @Assert\Valid()
* @ORM\OneToMany(targetEntity="Course", mappedBy="user", cascade={"persist", "remove"})
*/
private $courses;
public function getCompany()
{
return $this->company;
}
public function setCompany(Company $company = null)
{
$this->company = $company;
}
public function isEmployee()
{
return in_array('ROLE_EMPLOYEE', $this->roles);
}
public function isEmployer()
{
return in_array('ROLE_EMPLOYER', $this->roles);
}
public function isEqualTo(UserInterface $user) {
return $this->email === $user->getEmail();
}
/**
* @inheritDoc
*/
public function eraseCredentials()
{
}
public function serialize()
{
return \serialize(array(
$this->id,
$this->email
));
}
public function unserialize($serialized)
{
list (
$this->id,
$this->email
) = \unserialize($serialized);
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return $this->enabled;
}
public function getSalt()
{
return null;
}
public function getPassword()
{
return $this->password;
}
public function getRoles()
{
return $this->roles;
}
public function getUsername()
{
return $this->email;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set email
*
* @param string $email
*
* @return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set password
*
* @param string $password
*
* @return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Set accountNonExpired
*
* @param boolean $accountNonExpired
*
* @return User
*/
public function setAccountNonExpired($accountNonExpired)
{
$this->accountNonExpired = $accountNonExpired;
return $this;
}
/**
* Get accountNonExpired
*
* @return boolean
*/
public function getAccountNonExpired()
{
return $this->accountNonExpired;
}
/**
* Set accountNonLocked
*
* @param boolean $accountNonLocked
*
* @return User
*/
public function setAccountNonLocked($accountNonLocked)
{
$this->accountNonLocked = $accountNonLocked;
return $this;
}
/**
* Get accountNonLocked
*
* @return boolean
*/
public function getAccountNonLocked()
{
return $this->accountNonLocked;
}
/**
* Set credentialsNonExpired
*
* @param boolean $credentialsNonExpired
*
* @return User
*/
public function setCredentialsNonExpired($credentialsNonExpired)
{
$this->credentialsNonExpired = $credentialsNonExpired;
return $this;
}
/**
* Get credentialsNonExpired
*
* @return boolean
*/
public function getCredentialsNonExpired()
{
return $this->credentialsNonExpired;
}
/**
* Set enabled
*
* @param boolean $enabled
*
* @return User
*/
public function setEnabled($enabled)
{
$this->enabled = $enabled;
return $this;
}
/**
* Get enabled
*
* @return boolean
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Set actionToken
*
* @param string $actionToken
*
* @return User
*/
public function setActionToken($actionToken)
{
$this->actionToken = $actionToken;
return $this;
}
/**
* Get actionToken
*
* @return string
*/
public function getActionToken()
{
return $this->actionToken;
}
/**
* Set roles
*
* @param array $roles
*
* @return User
*/
public function setRoles($roles)
{
$this->roles = $roles;
return $this;
}
/**
* Set terms
*
* @param boolean $terms
*
* @return User
*/
public function setTerms($terms)
{
$this->terms = $terms;
return $this;
}
/**
* Get terms
*
* @return boolean
*/
public function getTerms()
{
return $this->terms;
}
/**
* Set description
*
* @param string $description
*
* @return User
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set firstname
*
* @param string $firstname
*
* @return User
*/
public function setFirstname($firstname)
{
$this->firstname = $firstname;
return $this;
}
/**
* Get firstname
*
* @return string
*/
public function getFirstname()
{
return $this->firstname;
}
/**
* Set lastname
*
* @param string $lastname
*
* @return User
*/
public function setLastname($lastname)
{
$this->lastname = $lastname;
return $this;
}
/**
* Get lastname
*
* @return string
*/
public function getLastname()
{
return $this->lastname;
}
/**
* Set birthday
*
* @param string $birthday
*
* @return User
*/
public function setBirthday($birthday)
{
$this->birthday = $birthday;
return $this;
}
/**
* Get birthday
*
* @return string
*/
public function getBirthday()
{
return $this->birthday;
}
/**
* Set residence
*
* @param string $residence
*
* @return User
*/
public function setResidence($residence)
{
$this->residence = $residence;
return $this;
}
/**
* Get residence
*
* @return string
*/
public function getResidence()
{
return $this->residence;
}
/**
* Set giodoContact
*
* @param boolean $giodoContact
*
* @return User
*/
public function setGiodoContact($giodoContact)
{
$this->giodoContact = $giodoContact;
return $this;
}
/**
* Get giodoContact
*
* @return boolean
*/
public function getGiodoContact()
{
return $this->giodoContact;
}
/**
* Set giodoInformation
*
* @param boolean $giodoInformation
*
* @return User
*/
public function setGiodoInformation($giodoInformation)
{
$this->giodoInformation = $giodoInformation;
return $this;
}
/**
* Get giodoInformation
*
* @return boolean
*/
public function getGiodoInformation()
{
return $this->giodoInformation;
}
/**
* Constructor
*/
public function __construct()
{
$this->experiences = new \Doctrine\Common\Collections\ArrayCollection();
$this->educations = new \Doctrine\Common\Collections\ArrayCollection();
$this->languages = new \Doctrine\Common\Collections\ArrayCollection();
$this->courses = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add experience
*
* @param \AppBundle\Entity\Experience $experience
*
* @return User
*/
public function addExperience(\AppBundle\Entity\Experience $experience)
{
$experience->setUser($this);
$this->experiences[] = $experience;
return $this;
}
/**
* Remove experience
*
* @param \AppBundle\Entity\Experience $experience
*/
public function removeExperience(\AppBundle\Entity\Experience $experience)
{
$this->experiences->removeElement($experience);
}
/**
* Get experiences
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getExperiences()
{
return $this->experiences;
}
/**
* Add education
*
* @param \AppBundle\Entity\Education $education
*
* @return User
*/
public function addEducation(\AppBundle\Entity\Education $education)
{
$education->setUser($this);
$this->educations[] = $education;
return $this;
}
/**
* Remove education
*
* @param \AppBundle\Entity\Education $education
*/
public function removeEducation(\AppBundle\Entity\Education $education)
{
$this->educations->removeElement($education);
}
/**
* Get educations
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getEducations()
{
return $this->educations;
}
/**
* Add language
*
* @param \AppBundle\Entity\Language $language
*
* @return User
*/
public function addLanguage(\AppBundle\Entity\Language $language)
{
$language->setUser($this);
$this->languages[] = $language;
return $this;
}
/**
* Remove language
*
* @param \AppBundle\Entity\Language $language
*/
public function removeLanguage(\AppBundle\Entity\Language $language)
{
$this->languages->removeElement($language);
}
/**
* Get languages
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getLanguages()
{
return $this->languages;
}
/**
* Add course
*
* @param \AppBundle\Entity\Course $course
*
* @return User
*/
public function addCourse(\AppBundle\Entity\Course $course)
{
$course->setUser($this);
$this->courses[] = $course;
return $this;
}
/**
* Remove course
*
* @param \AppBundle\Entity\Course $course
*/
public function removeCourse(\AppBundle\Entity\Course $course)
{
$this->courses->removeElement($course);
}
/**
* Get courses
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCourses()
{
return $this->courses;
}
}
And for example - language entity - Language.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Language
*
* @ORM\Table(name="languages")
* @ORM\Entity
*
*/
class Language
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(message="To pole jest wymagane. ")
*/
private $name;
/**
* @ORM\Column(type="string", length=256)
* @Assert\NotBlank(message="To pole jest wymagane. ")
*/
private $level;
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="languages")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
*/
private $user;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return Language
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set level
*
* @param string $level
*
* @return Language
*/
public function setLevel($level)
{
$this->level = $level;
return $this;
}
/**
* Get level
*
* @return string
*/
public function getLevel()
{
return $this->level;
}
/**
* Set user
*
* @param \AppBundle\Entity\User $user
*
* @return Language
*/
public function setUser(\AppBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* @return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
}
And language form - LanguageType.php:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Doctrine\ORM\EntityRepository;
class LanguageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', ChoiceType::class, array(
'choices' => array(
'angielski' => 'angielski',
'niemiecki' => 'niemiecki'
),
'label' => 'Język'
))
->add('level', ChoiceType::class, array(
'choices' => array(
'A1' => 'A1',
'A2' => 'A2',
'B1' => 'B1',
'B2' => 'B2',
'C1' => 'C1',
'C2' => 'C2'
),
'label' => 'Poziom'
))
->add('save', SubmitType::class, array(
'label' => 'Zapisz i zaaktualizuj informacje',
'attr' => array('class' => 'button button-primary button-md')
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Language',
));
}
}
To sum up - I don't display form in the custom way, only the method from the documentation. As I wrote above the main problem is how to save item after removing it, when there's no submit button. If you need more details, please let me know.
I really appreciate your help.
Thanks, best regards
PS I don't know if there's any possibility to turn on syntax highlighting on github issues. Sorry for that.
@ninsuo Any idea what am I doing wrong?
Hi,
you can try to delete on your form the submit button. And add it on twig view.
You can write something like this :
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.field1) }}
<button type="submit" class="your-class" title="">Submit</button>
{{ form_rest(form) }}
{{ form_end(form) }}
That's print you form row by row, and create one submit button at the end of the form.
For the control button, i don't know sorry.