Robbo_UK
Robbo_UK

Reputation: 12149

Symfony2 - Dynamic form choices - validation remove

I have a drop down form element. Initially it starts out empty but it is populated with values via javascript after the user has made some interactions. Thats all working ok. However when I submit it always returns a validation error This value is not valid..

If I add the items to the choices list in the form code it will validate OK however I am trying to populate it dynamically and pre adding the items to the choices list is not going to work.

The problem I think is because the form is validating against an empty list of items. I don't want it to validate against a list at all. I have set validation required to false. I switched the chocie type to text and that always passes validation.

This will only validate against empty rows or items added to choice list

$builder->add('verified_city', 'choice', array(
  'required' =>  false
));

Similar question here that was not answered.
Validating dynamically loaded choices in Symfony 2

Say you don't know what all the available choices are. It could be loaded in from a external web source?

Upvotes: 13

Views: 16556

Answers (5)

ssrp
ssrp

Reputation: 1266

Add this inside buildForm method in your form type class so that you can validate an input field value rather a choice from a select field value;

$builder->addEventListener(
    FormEvents::PRE_SUBMIT,

    function (FormEvent $event) {
        $form = $event->getForm();

        if ($form->has('verified_city')) {
            $form->remove('verified_city');
            $form->add(
                'verified_city', 
                'text', 
                ['required' => false]
            )
        }
    }
);

Upvotes: 0

Thiru
Thiru

Reputation: 37

Update in Validations.yml

Kindly update the Validation.yml file in the below format : setting the group names in the each field

 
         password:
            - NotBlank: { message: Please enter password ,groups: [Default]}
Update in Form Type /** * @param OptionsResolverInterface $resolver */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'RegistrationBundle\Entity\sf_members', 'validation_groups' => function(FormInterface $form){
$data = $form->getData();
$member_id = $data->getMemberId();

// Block of code; // starts Here :

if( condition == 'edit profile') { return array('edit'); } else { return array('Default'); } },

Update in Entity /** * @var string * * @ORM\Column(name="password", type="text") * @Assert\Regex( * pattern="/(?i)^(?=.[a-zA-Z])(?=.\d).{8,}$/", * match=true, * message="Your password must be at least 8 characters, including at least one number and one letter", * groups={"Default","edit"} * ) */
private $password;

Upvotes: -1

Atan
Atan

Reputation: 1113

Found a better solution which I posted here: Disable backend validation for choice field in Symfony 2 Type

Old answer:

Just spent a few hours dealing with that problem. This choice - type is really annoying. My solution is similar to yours, maybe a little shorter. Of course it's a hack but what can you do...

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('place', 'choice'); //don't validate that

    //... more form fields

   //before submit remove the field and set the submitted choice as
   //"static" choices to make "ChoiceToValueTransformer" happy
   $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();
        if ($form->has('place')) {
            $form->remove('place');
        }

        $form->add('place', 'choice', array(
            'choices' => array($data['place']=>'Whatever'),
        ));
    });
}

Upvotes: 0

Robbo_UK
Robbo_UK

Reputation: 12149

after much time messing around trying to find it. You basically need to add a PRE_BIND listener. You add some extra choices just before you bind the values ready for validation.

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;


public function buildForm(FormBuilderInterface $builder, array $options)
{

  // .. create form code at the top

    $ff = $builder->getFormFactory();

    // function to add 'template' choice field dynamically
    $func = function (FormEvent $e) use ($ff) {
      $data = $e->getData();
      $form = $e->getForm();
      if ($form->has('verified_city')) {
        $form->remove('verified_city');
      }


      // this helps determine what the list of available cities are that we can use
      if ($data instanceof  \Portal\PriceWatchBundle\Entity\PriceWatch) {
        $country = ($data->getVerifiedCountry()) ? $data->getVerifiedCountry() : null;
      }
      else{
        $country = $data['verified_country'];
      }

      // here u can populate choices in a manner u do it in loadChoices use your service in here
      $choices = array('', '','Manchester' => 'Manchester', 'Leeds' => 'Leeds');

      #if (/* some conditions etc */)
      #{
      #  $choices = array('3' => '3', '4' => '4');
      #}
      $form->add($ff->createNamed('verified_city', 'choice', null, compact('choices')));
    };

    // Register the function above as EventListener on PreSet and PreBind

    // This is called when form first init - not needed in this example
    #$builder->addEventListener(FormEvents::PRE_SET_DATA, $func); 

    // called just before validation 
    $builder->addEventListener(FormEvents::PRE_BIND, $func);  

}

Upvotes: 7

William Durand
William Durand

Reputation: 5519

The validation is handled by the Validator component: http://symfony.com/doc/current/book/validation.html.

The required option in the Form layer is used to control the HTML5 required attribute, so it won't change anything for you, and that is normal.

What you should do here is to configure the Validation layer according to the documentation linked above.

Upvotes: 0

Related Questions