Короткий вопрос длиной
, после долгих исследований об этом и нахождения некоторой информации о том, как расширить существующие типы полей, или наследовать от них, или изменить некоторые вещи в бэкэнде, но абсолютно ничего для фактического рендеринга во внешнем интерфейсе, Я иду сюда, чтобы задать вопрос.
Краткое пояснение к обсуждаемой проблеме:
Мне нужно поле EntityType (ChoiceType - HTML Select), чтобы использовать собственную логику фильтрации и динамически извлекать результаты из вызова ajax, мгновенно заменяя параметры, перечисленные в раскрывающемся списке.
Текущий код (работает):
в FormType.php
//in buildForm
{
$builder->add('trainer', EntityType::class, [
'class' => Trainer::class,
'choices' => $training->trainer_list ?? [],
'label' => 'seminar.trainer.form.trainer.label',
'placeholder' => 'form.trainer.placeholder',
'required' => false,
'attr' => ['class' => 'trainer2select'] // has no outcome whatsoever?!
])
$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']);
}
function onPreSubmit(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$trainer = $this->em->getRepository(Trainer::class)->find($data['trainer']);
$form->add('trainer', EntityType::class, [
'class' => Trainer::class,
'data' => $trainer,
'label' => 'seminar.trainer.form.trainer.label',
'placeholder' => 'form.trainer.placeholder',
'required' => false,
]);
}
И в веточку:
{% if field == 'trainer' %}
{{ form_row(attribute(form, field), {'id': 'trainer'}) }}
{% else %}
{{ form_row(attribute(form, field)) }}
{% endif %}
{% block javascripts %}
<script>
var lastTime;
var timeoutEvents = [];
$(document).ready(() => {
function trainer_changed() {
let input = event.target;
lastTime = Date.now();
timeoutEvents.push(setTimeout(() => {
if (Date.now() - lastTime < 150)
return;
jQuery.ajax({
url: '{{ path('trainer_select_ajax') }}',
type: 'GET',
data: {
search: input.value,
start: {{ seminar.event.start.date | date('Y-m-d') }},
end: {{ seminar.event.end.date | date('Y-m-d') }}
},
success: function (trainers) {
let trainer = $('#trainer');
trainer.get(0).options.length = 1; // reset all options, except for the default
trainers.forEach(tr => {
trainer.append(new Option(tr.text, tr.id));
});
let search = $($("input.select2-search__field").get(1));
if (search.get(0)) {
search.get(0).oninput = null; // detach our event handler so we don't loop
search.trigger('input'); // rebuild the dropdown choices
search.get(0).oninput = trainer_changed; // reattach our event handler
}
}
});
lastTime = Date.now();
timeoutEvents.forEach(e => {
clearTimeout(e);
});
}, 200));
}
function select_opened() {
let trainerinput = $('input.select2-search__field').get(1);
if (trainerinput) {
trainerinput.oninput = trainer_changed;
}
}
$('#select2-trainer-container').click(select_opened);
});
</script>
{% endblock %}
Итак, по-видимому, поле EntityType визуализируется с использованием расширения select2. Очевидно, что я могу заменить функциональность javascript, но я бы хотел просто определить свой собственный AjaxEntityType, который form_widget отображает так, как я хочу. Что-то, что я могу использовать в нескольких проектах, без использования некоторых глупых хаков, таких как предоставление имени класса по умолчанию и вызов javascript, который изменяет рендеринг после загрузки страницы глобально. Итак ... как дела?
Ресурсы, которые я проверил, которые оказались бесполезными для того, чего я хочу достичь: https://symfony.com/doc/current/form/form_customization.html, https://symfony.com/doc/current/form/form_themes.html и многое другое.
Редактировать для пояснения: оптимально, что я ищу, это минималистичный пример пользовательского FieldType, всегда отображаемого как <select id="FieldTypeWidget">
, для которого всегда будет вызываться $('#FieldTypeWidget').select2({ajax: {foo}, searchFunction: {bar}});
at https://github.com/tetranz/select2entity-bundle Я могу найти пример того, как предоставить эту функцию в комплекте, но есть ли более простой способ только в моем приложении?