Symfony2:使用ajax和验证来更改选项

时间:2022-10-22 18:18:08

Scenario: I have a form with 2 selects. When user selects something from the first select, the second select gets populated with new values. This part works fine.

场景:我有一个有2个选择的表单。当用户从第一个选择中选择某些内容时,第二个选择将填充新值。这部分工作正常。

But the form does not get validated since it contains some choices that are not allowed in the initial form.

但是表单没有得到验证,因为它包含初始表单中不允许的一些选项。

Form:

形成:

<?php

class MyType extends AbstractType
{
    private $category;

    public function __construct($category = null)
    {
        $this->category = $category;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('category', 'choice', array(
            'choices' => array(
                'foo' => 'foo',
                'bar' => 'bar'
            )
        );

        $builder->add('template', 'choice', array(
            'choices' => $this->loadChoices()
        );
    }

    private function loadChoices()
    {
        // load them from DB depending on the $this->category
    }
}

Initially the category is foo. So the templates for foo get loaded and set as choices. But if the user selects bar, the bar templates get loaded. But the form still has the foo choices and does not validate.

最初的类别是foo。因此foo的模板被加载并设置为选项。但是,如果用户选择了条形,则会加载条形模板。但是表单仍然有foo选择而且没有验证。

What is the best way to solve this?

解决这个问题的最佳方法是什么?

One way I found was to just reinitiate the form in the controller:

我找到的一种方法是重新启动控制器中的表单:

<?php

$form = $this->createForm(new MyType());

if ($request->getMethod() === 'POST') {
    if ($request->request->has($form->getName())
        && isset($request->request->get($form->getName())['category'])) {
            $form = $this->createForm(new MyType($request->request->get($form->getName())['category']));
    }

    // ...
}

This works, but I cannot test it because it throws IllegalArgumentException when setting the value and just assumes default. Is there any better solution to this? Thanks in advance!

这可行,但我无法测试它,因为它在设置值时抛出IllegalArgumentException并且只是假定为默认值。有没有更好的解决方案呢?提前致谢!

1 个解决方案

#1


21  

I think u have to use Events to manage this, which is more correct way

我认为你必须使用事件来管理这个,这是更正确的方法

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('category', 'choice', array(
        'choices' => array(
            'foo' => 'foo',
            'bar' => 'bar'
        )
    ));

    $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('template')) {
            $form->remove('template');
        }

        $cat = isset($data['category'])?$data['category']:null;

        // here u can populate ur choices in a manner u do it in loadChoices
        $choices = array('1' => '1', '2' => '2');
        if ($cat == 'bar') {
            $choices = array('3' => '3', '4' => '4');
        }

        $form->add($ff->createNamed('template', 'choice', null, compact('choices')));
    };

    // Register the function above as EventListener on PreSet and PreBind
    $builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
    $builder->addEventListener(FormEvents::PRE_BIND, $func);
}

#1


21  

I think u have to use Events to manage this, which is more correct way

我认为你必须使用事件来管理这个,这是更正确的方法

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('category', 'choice', array(
        'choices' => array(
            'foo' => 'foo',
            'bar' => 'bar'
        )
    ));

    $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('template')) {
            $form->remove('template');
        }

        $cat = isset($data['category'])?$data['category']:null;

        // here u can populate ur choices in a manner u do it in loadChoices
        $choices = array('1' => '1', '2' => '2');
        if ($cat == 'bar') {
            $choices = array('3' => '3', '4' => '4');
        }

        $form->add($ff->createNamed('template', 'choice', null, compact('choices')));
    };

    // Register the function above as EventListener on PreSet and PreBind
    $builder->addEventListener(FormEvents::PRE_SET_DATA, $func);
    $builder->addEventListener(FormEvents::PRE_BIND, $func);
}