Open r3m4k3 opened 8 years ago
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.
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