Symfony-自定义FieldType form_widget呈现

时间:2019-03-12 20:19:53

标签: javascript php symfony twig widget

长话短说,经过大量研究并找到了很多有关如何扩展现有字段类型,如何继承它们或在后端进行某些更改的信息,但对于前端中的实际呈现却一无所知,我是来问这个问题的。

对手头“问题”的简短解释: 我需要一个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替换该功能,但是我只想定义自己的form_widget呈现的“ AjaxEntityType”即可。我可以在多个项目中使用某些东西,而无需使用一些愚蠢的技巧,例如提供默认的类名以及在页面全局加载后调用javascript更改该呈现。那...怎么办?

我检查过的资源对我想要实现的目标几乎毫无价值:https://symfony.com/doc/current/form/form_customization.htmlhttps://symfony.com/doc/current/form/form_themes.html等。

为清楚起见进行编辑:最佳地,我想要的是一个简单的示例,该示例始终将自定义FieldType呈现为<select id="FieldTypeWidget">,并在其上始终调用$('#FieldTypeWidget').select2({ajax: {foo}, searchFunction: {bar}});

https://github.com/tetranz/select2entity-bundle,我可以找到一个如何捆绑提供此功能的示例,但是在我的应用程序中是否有更简单的方法?

0 个答案:

没有答案