0
votes

basic information: Visualization

In TrainingType.php that creates the form:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('trainer', EntityType::class, [
            'class' => 'AppBundle:Trainer',
            'choices' => $training->trainer_list ?? null,
            'label' => 'seminar.trainer.form.trainer.label',
            'placeholder' => 'form.trainer.placeholder',
            'required' => false,
    ]);
    $builder->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'onPreSetData']); // update 'trainer'
    $builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']); // update 'trainer'
}

in twig:

{% if field == 'trainer' %}
    {{ form_row(attribute(form, field), {'id': 'trainer'}) }}
{% endif %}

javascript (test):

<script>
    $(document).ready(() => {
        function trainer_changed() {
            let trainer = $('#trainer');
            jQuery.ajax({
                url: '{{ path('trainer_select_ajax') }}',
                type: 'GET',
                data: {
                    //this is the id of the selected option, not the search term
                    search: trainer.val() 
                },
                success: function (html) {
                    let trainer = $('#trainer');
                    let newchoices = $(html).find('#trainer');
                    trainer.replaceWith(
                        newchoices  // works
                    );
                }
            });
        }
        // when a new option is selected, not what I want
        $('#trainer').change(trainer_changed);
        $('#trainer').on('input', trainer_changed);  // no effect
    });
</script>

The choice list should be updated while typing 'foo' It currently shows no selectable options because it doesn't find results for "foo" in the preloaded data, even though if the ajax call to the server sent "foo", it would return results for it.

So my question is how to put an "oninput" or "onchange" listener on the search field as shown in the image. When I start typing it should fetch the updated choicelist from the server via ajax call and instantly replace it in the dropdown.

I've yet failed to even select the search field. Symfony's documentation at https://symfony.com/doc/3.4/form/dynamic_form_modification.html does not help at all, because all those example events are only fired when something is actually selected, not when just typing a search term.

Bonus, though I guess I have an idea how to do that just reformatting the entries with javascript, I'd like to be able to show each option as 'LastName, FirstName - Title - Priceā‚¬', instead of the 'LastName, FirstName' (__toString() method of the Trainer Entity) that Symfony itself uses. So I guess, I'd like to get Symfony to use a different method than __toString() for this specific form row.

1

1 Answers

0
votes

The "solution" was to first wait until the dropdown is opened and then attach the oninput listener to the input field.

<script>
    $(document).ready(() => {
        function trainer_changed() {
            let input = event.target;
            jQuery.ajax({
                url: '{{ path('trainer_select_ajax') }}',
                type: 'GET',
                data: {
                    search: input.value
                },
                success: function (trainers) {
                    let trainer = $('#trainer')[0];
                    trainer.options.length = 1;  // reset all options, except for the default
                    trainers.forEach((tr, idx) => {
                        trainer[idx+1] = new Option(tr.name, tr.id);
                    });
                }
            });
        }
        function select_opened() {
            let trainercontainer = $('select2-container select2-container--default select2-container--open');
            if (trainercontainer) {
                let trainerinput = trainercontainer.prevObject[0].activeElement;  // input field
                trainerinput.oninput = trainer_changed;
            }
        }
        $('#select2-trainer-container').click(select_opened);
    });
</script>

To update the rendered dropdown instantly, use $('input.select2__field').trigger('change');