2012-11-10 14 views
19

シナリオ:2つの選択肢があるフォームがあります。ユーザーが最初の選択から何かを選択すると、2番目の選択に新しい値が設定されます。この部分はうまく動作します。Symfony2:ajaxと検証で選択肢を変更してください。

しかし、初期フォームでは許可されていない選択肢が含まれているため、フォームは検証されません。

フォーム:

<?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 
    } 
} 

当初カテゴリがfooです。したがって、fooのテンプレートはロードされ、選択肢として設定されます。しかし、ユーザがbarを選択すると、バーテンプレートがロードされます。しかしフォームにはまだfooの選択肢があり、検証はしません。

これを解決する最良の方法は何ですか?

私が見つけた一つの方法は、単にコントローラでフォームを再開しました:

<?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'])); 
    } 

    // ... 
} 

これは動作しますが、それは値を設定するときIllegalArgumentExceptionをスローし、単にデフォルトを想定しているので、私はそれをテストすることはできません。これにはもっと良い解決策がありますか?前もって感謝します!

+0

である、uはこれを管理するためにイベントを使用する必要がありますと思いますか?次に、あなたに関連するグループでのみバリデータサービスを呼び出すことができます。 http://symfony.com/doc/2.0/book/forms.html#validation-groups – Xocoatzin

答えて

20

私はあなたが検証しなければならないオプションの各セットの検証グループを設定しようとしたことがあり、より正しい方法

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); 
} 
+0

申し訳ありません。私は今日それをチェックします。 :) – smottt

+0

完璧に動作します、ありがとう! – smottt

+0

私は、(onChange'トリガーでAJAXを使用するために探していた)同様の問題を解決するためにこのリンクを推奨しました。すべての変更前にチェックしたかったのですが、フォームを更新せずにフォームをリフレッシュして、フォームを送信せずにカテゴリを選択したときにデータベース参照から 'template'ドロップダウンを読み込むことはできますか? – Bendy

関連する問題