很长的问题--简短地说,在对此进行了大量的研究之后,发现了一些关于如何扩展现有字段类型的信息,或者继承了它们,或者在后端更改了一些东西,但是对于前端的实际渲染,我完全没有,我是来问这个问题的。
对当前“问题”的简短解释:我需要一个EntityType字段(ChoiceType - HTML )来使用我自己的过滤逻辑,并动态地从ajax调用中提取结果,立即替换下拉列表中列出的选项。
当前代码(works):在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,在全局加载页面后更改呈现。所以..。怎么做?
我已经检查过的资源,这些资源对我想要实现的目标来说是毫无价值的:customization.html、themes.html和更多的资源。
编辑以获得澄清:我想要的是一个极简的示例,说明自定义FieldType总是被呈现为<select id="FieldTypeWidget">,在这个示例中总是会调用$('#FieldTypeWidget').select2({ajax: {foo}, searchFunction: {bar}});
在https://github.com/tetranz/select2entity-bundle,我可以找到一个例子,说明如何在一个包中提供这个功能,但是在我的应用程序中有更简单的方法吗?
发布于 2019-03-12 22:39:05
我想说的是,你所看到的是在这个Symfony文档页面中解释的
下面是针对您的需要进行了一些修改的示例:
src/Form/Type/AjaxEntityType.php
<?php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EntityType;
class AjaxEntityType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
/**
* This is the default of your field,
* add or remove based on your needs,
* your goal, is to only keep sensible defaults
* that you want on every single objects of this class
*/
'required' => false,
]);
}
public function getParent()
{
return EntityType::class;
}
}这就是“魔法”发生的地方:
当您的类被称为WhateverNameType,时,Symfony将只删除它的类型部分,并将其规范化(简化后的lcfirst it)。
所以WhateverNameType将以whateverName.结尾
然后,您只需知道表单元素是被调用的,在呈现whateverName_widget form_widget中就可以得到正确命名的块:
模板/表单/form s.html.twig
{% use 'form_div_layout.html.twig' %}
{% block ajaxEntity_widget %}
{{ parent() }}
<script>
$('#{{ form.vars.id }}').select2({ajax: {foo}, searchFunction: {bar}});
</script>
{% endblock %}还请注意文档页面中的便利提示:
您可以进一步自定义用于呈现所选类型的每个子级的模板。在这种情况下,要重写的块名为“块名”+ entry + "element name“(标签、错误或小部件)(例如,要自定义航运小部件的子部件的标签,就需要定义{%块shipping_entry_label %} . {% endblock %})。
还请记住,正如稍后仍在同一页中指出的,表单模板覆盖必须正确注册:
config/packages/twig.yaml
twig:
form_themes:
- 'form/fields.html.twig'
# you might have this configuration already,
# for example, if you use bootstrap theming.
# If so, just copy the configured template path stated here
# in the 'use' statement of the file form/fields.html.twig那就用它吧:
$builder->add('trainer', AjaxEntityType::class, [ class => Trainer::class, ]);也值得一读:
https://stackoverflow.com/questions/55130038
复制相似问题