Поиск…
Как расширить ChoiceType, EntityType и DocumentType для загрузки вариантов с помощью AJAX.
В Symfony встроенный ChoiceType (и EntityType или DocumentType, расширяющий его), в основном работает с постоянным списком выбора.
Если вы хотите, чтобы он работал с ajax-звонками, вы должны изменить их, чтобы принимать любые сухие дополнительные варианты.
Как начать с пустого списка?
Когда вы создаете форму, просто установите опцию
choices
в пустойarray()
:namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; class FooType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('tag', ChoiceType::class, array('choices'=>array())); } }
Таким образом, вы получите пустой выбор ввода без выбора. Это решение работает для ChoiceType и всех его детей (EntityType, DocumentType, ...).
Как принять представленные новые варианты :
Чтобы принять новые варианты, вы должны сделать их доступными в списке выбора полей формы. Вы можете изменить поле формы в зависимости от представленных данных с событием FormEvent :: PRE_SUBMIT.
В этом примере показано, как это сделать с помощью базового ChoiceType:
namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; class FooType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('tag', ChoiceType::class, array('choices'=>array())) ; $builder->addEventListener( FormEvents::PRE_SUBMIT, function(FormEvent $event){ // Get the parent form $form = $event->getForm(); // Get the data for the choice field $data = $event->getData()['tag']; // Collect the new choices $choices = array(); if(is_array($data)){ foreach($data as $choice){ $choices[$choice] = $choice; } } else{ $choices[$data] = $data; } // Add the field again, with the new choices : $form->add('tag', ChoiceType::class, array('choices'=>$choices)); } ); } }
Теперь вашим избранным выборам разрешено выбирать, а встроенная проверка Symfony ChoiceType больше не будет их отклонять.
Если вы хотите сделать то же самое с дочерним элементом ChoiceType (EntityType, DocumentType, ...), вам нужно ввести entityManager или documentManager и сделать datatransformation при заполнении новых вариантов.
Заполните поле выбора в зависимости от значения другого.
Это пример, показывающий, как изменить разрешенные варианты в поле выбора подкатегории в зависимости от значения поля выбора категории. Для этого вы должны сделать выбор своей подкатегории динамичным как для клиента, так и для сервера.
1. Сделайте динамическую форму на стороне клиента для взаимодействия с дисплеем / пользователем
Пример динамической формы клиентской стороны (с использованием Javascript / JQuery):
$('#category').change(function(){
switch($(this).val()){
case '1': // If category == '1'
var choice = {
'choice1_1':'1_1',
'choice1_2':'1_2',
'choice1_3':'1_3',
};
break;
case '2': // If category == '2'
var choice = {
'choice2_1':'2_1',
'choice2_2':'2_2',
'choice2_3':'2_3',
};
break;
case '3': // If category == '3'
var choice = {
'choice3_1':'3_1',
'choice3_2':'3_2',
'choice3_3':'3_3',
};
break;
}
var $subCategorySelect = $('#subCategory');
$subCategorySelect.empty();
$.each(choice, function(key, value) {
$subCategorySelect.append($('<option></option>')).attr('value',value).text(key);
});
});
Конечно, вы можете получить выбор из звонка AJAX. Это не цель этого примера.
2. Сделайте динамическую форму на стороне сервера для инициализации / проверки
Пример динамической формы на стороне сервера:
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class MyBaseFormType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('category',ChoiceType::class,array('choices'=>array(
'choice1'=>'1',
'choice2'=>'2',
'choice3'=>'3',
)))
;
$addSubCategoryListener = function(FormEvent $event){
$form = $event->getForm();
$data = $event->getData();
switch($data['category']){
case '1': // If category == '1'
$choices = array(
'choice1_1'=>'1_1',
'choice1_2'=>'1_2',
'choice1_3'=>'1_3',
);
break;
case '2': // If category == '2'
$choices = array(
'choice2_1'=>'2_1',
'choice2_2'=>'2_2',
'choice2_3'=>'2_3',
);
break;
case '3': // If category == '3'
$choices = array(
'choice3_1'=>'3_1',
'choice3_2'=>'3_2',
'choice3_3'=>'3_3',
);
break;
}
$form->add('subCategory',ChoiceType::class,array('choices'=>$choices));
};
// This listener will adapt the form with the data passed to the form during construction :
$builder->addEventListener(FormEvents::PRE_SET_DATA, $addSubCategoryListener);
// This listener will adapt the form with the submitted data :
$builder->addEventListener(FormEvents::PRE_SUBMIT, $addSubCategoryListener);
}
}