Проверка динамически загружаемых вариантов в Symfony 2
У меня есть тип поля выбора с именем * sub_choice * в моей форме, выбор которого будет динамически загружаться через AJAX в зависимости от выбранного значения поля выбора родителя с именем * parent_choice *. Загрузка вариантов работает отлично, но я столкнулся с проблемой при проверке значения sub_choice при представлении. Он дает ошибку "Это значение недействительно", поскольку представленное значение не находится в выборе поля sub_choice при его создании. Итак, можно ли правильно проверить поданное значение поля sub_choice? Ниже приведен код для создания моей формы. Я использую Symfony 2.1.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('parent_choice', 'entity', array(
'label' => 'Parent Choice',
'class' => 'Acme\TestBundle\Entity\ParentChoice'
));
$builder->add('sub_choice', 'choice', array(
'label' => 'Sub Choice',
'choices' => array(),
'virtual' => true
));
}
Ответы
Ответ 1
Чтобы выполнить трюк, вам необходимо перезаписать поле sub_choice
перед отправкой формы:
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$parentChoice = $event->getData();
$subChoices = $this->getValidChoicesFor($parentChoice);
$event->getForm()->add('sub_choice', 'choice', [
'label' => 'Sub Choice',
'choices' => $subChoices,
]);
});
}
Ответ 2
это принимает любое значение
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
if(is_array($data['tags']))$data=array_flip($data['tags']);
else $data = array();
$event->getForm()->add('tags', 'tag', [
'label' => 'Sub Choice',
'choices' => $data,
'mapped'=>false,
'required'=>false,
'multiple'=>true,
]);
});
Ответ 3
Добавление альтернативного подхода для будущих читателей, так как мне пришлось много исследовать, чтобы заставить мою форму работать. Вот разбивка:
- Добавление "новой" опции в выпадающий список с помощью jquery
- Если выбран "Новый", отобразите новое поле формы "Пользовательский параметр".
- Представить форму
- Проверить данные
- Сохранить в базе данных
JQuery код для ветки:
$(function(){
$(document).ready(function() {
$("[name*='[custom_option]']").parent().parent().hide(); // hide on load
$("[name*='[options]']").append('<option value="new">New</option>'); // add "New" option
$("[name*='[options]']").trigger("chosen:updated");
});
$("[name*='[options]']").change(function() {
var companyGroup = $("[name*='[options]']").val();
if (companyGroup == 'new') { // when new option is selected display text box to enter custom option
$("[name*='[custom_option]']").parent().parent().show();
} else {
$("[name*='[custom_option]']").parent().parent().hide();
}
});
});
// Here my Symfony 2.6 form code:
->add('options', 'entity', [
'class' => 'Acme\TestBundle\Entity\Options',
'property' => 'display',
'empty_value' => 'Select an Option',
'mapped' => true,
'property_path' => 'options.optionGroup',
'required' => true,
])
->add('custom_option', 'text', [
'required' => false,
'mapped' => false,
])
Для обработки данных формы нам нужно использовать событие формы PRE_SUBMIT.
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (isset($data['options']) && $data['options'] === 'new') {
$customOption = $data['custom_option'];
// todo: handle this better on your own
if (empty($customOption)) {
$form->addError(new FormError('Please provide a custom option'));
return;
}
// Check for a duplicate option
$matches = $this->doctrine->getRepository('Acme\TestBundle\Entity\Options')->matchByName([$customOption]);
if (count($matches) > 0) {
$form->addError(new FormError('Duplicate option found'));
return;
}
// More validation can be added here
// Creates new option in DB
$newOption = $this->optionsService->createOption($customOption); // return object after persist and flush in service
$data['options'] = $newOption->getOptionId();
$event->setData($data);
}
});
Дайте мне знать, если у вас возникнут вопросы или проблемы. Я знаю, что это может быть не лучшим решением, но оно работает. Спасибо!
Ответ 4
вы не можете построить подтверждение sub_choice, потому что во время настройки его валидатора вы не знаете, какие значения действительны (значения зависят от значения parent_choice).
Что вы можете сделать, так это разрешить parent_choice в сущности до того, как вы создадите новый YourFormType() в своем контроллере.
Затем вы можете получить все возможные значения для sub_choice и предоставить их по конструктору формы - новый YourFormType ($ subChoice).
В YourFormType вам нужно добавить метод __construct, подобный этому:
/**
* @var array
*/
protected $subChoice = array();
public function __construct(array $subChoice)
{
$this->subChoice = $subChoice;
}
и использовать предоставленные значения в форме add:
$builder->add('sub_choice', 'choice', array(
'label' => 'Sub Choice',
'choices' => $this->subChoice,
'virtual' => true
));
Ответ 5
Предположим, что для подвыборов у вас есть правильный номер?
Создайте и очистите массив с определенным количеством значений и дайте ему выбор
$indexedArray = [];
for ($i=0; $i<999; $i++){
$indexedArray[$i]= '';
}
then 'choices' => $indexedArray,
:)