Search code examples
javascriptphpfetch-apitom-select

How to prefill items in TomSelect when options are coming from remote (fetch API call)


I have a PHP app with a TomSelect dropdown which allows me to select persons who work on a site.

As this list is large, I fill in these options via a standard fetch call.

Here's my code sample (which works):

<select id="persons" placeholder="Pick an person..." multiple></select>

<script>

    var persons = new TomSelect("#persons", {
        maxOptions: 10,
        create: false,
        onItemAdd: function () {
            this.setTextboxValue('');
            this.refreshOptions();
        },
        
        valueField: 'id',
        labelField: 'completename',
        searchField: 'completename',

        items: [34276,2],
        
        // fetch remote data
        load: function(query, callback) {

            var url = 'http://host/api/staff?q=' + encodeURIComponent(query);
            fetch(url)
                .then((response) => response.json())
                .then(json => {
                    callback(json);
                }).catch(()=>{
                    callback();
            });

        },

        // custom rendering functions for options and items
        render: {
            option: function (data, escape) {
                return '<div class="d-flex"><span>' + escape(data.completename) + '</span></div>';
            },
            item: function (data, escape) {
                return '<span class="tag is-info mb-1 mr-1">' + escape(data.completename) + '</span>';
            }
        }
    });
    
</script>

Everything is saved properly to the database via PHP when the form is posted.

My question is about editing a site (when I come back to edit people assigned to a site).

How can I pre-select/pre-fill the people already assigned (34276 and 2 in the sample) and put them properly in the initial options. I have tried with the initial array items[], but this array only takes IDs of selectedValues but obviously not people's completenames.

I obviously have my PHP objects available like $site->getPersons() over which I can loop to get the IDs and completenames.

If I do it with an addOption and addItem afterwards, (or if I add the assigned people in HTML with an <option value="1" selected="selected">Roberta</option>) it works, but the behaviour is horrible because these pre-assigned people remain permanently at the start of the dropdown even when I deselect them and while the fetch API call is empty. As shown on the picture.

persons.addOption({
    id: 4,
    completename: 'Something New',
});

persons.addOption({
    id: 2,
    completename: 'Hans',
});

persons.addOption({
    id: 1,
    completename: 'Roberta',
});


persons.addItem(1);
persons.addItem(4);
persons.addItem(2);

enter image description here

Another shorter way of asking my question would be :

How to prevent my TomSelect dropdown (intended to receive options via fetch remote) from opening with "static" options added via addOption already visible.

I would like it to be empty until the fetch call has been made.


Solution

  • I found the solution.

    I just needed to add the persist:false option.

    As defined in the official TomSelect documentation:

    persist: If false, items created by the user will not show up as available options once they are unselected.

    Now, I can pre-fill items[] and delete them properly without polluting the dropdown.