slim-select icon indicating copy to clipboard operation
slim-select copied to clipboard

Feature request: fire event on new item being added to DOM via addable

Open kurthamilton opened this issue 5 months ago • 3 comments

Use case

I am displaying a long list of ordered options, allowing users to add their own values via the addable event. After a new item is added I would like to re-order the options in the dropdown.

Current workaround

I am currently storing the original state, and then on every afterChange event comparing the new values with the original values and re-creating the slim select instance.

This not only results in a flash of no content while re-creating slim select, but also a lot of boilerplate.

const selects = document.querySelectorAll('[data-slim-select]');
selects.forEach(select => {
    let slimSelect;
    const bindSelect = () => {
        if (slimSelect) {
            slimSelect.destroy();
        }
        const options = select.options;
        const originalValues = Array.from(options).map(x => x.innerText);
        slimSelect = new SlimSelect({
            select: select,
            events: {
                addable: value => value,
                afterChange: (newValue) => {
                    const newValues = newValue.filter(x => !originalValues.includes(x.text));
                    if (newValues.length === 0) {
                        return;
                    }

                    Array.from(options)
                        .sort((a, b) => a.innerText.localeCompare(b.innerText))
                        .forEach(node => select.appendChild(node));
                    bindSelect();
                }
            },
            settings: {}
        });
    };

    bindSelect();
});

Suggested solution

  1. Add an added event that fires after the DOM has been updated
  2. (nice to have) Add a rebuild method (or observe DOM mutations) that rebuilds the slim select list from the DOM
const selects = document.querySelectorAll('[data-slim-select]');
selects.forEach(select => {
    const slimSelect = new SlimSelect({
        select: select,
        events: {
            addable: value => value,
            /*** NEW 'ADDED' EVENT ***/
            added: (newValue) => {
                // re-order the DOM elements
                Array.from(options)
                    .sort((a, b) => a.innerText.localeCompare(b.innerText))
                    .forEach(node => select.appendChild(node));

                /*** NEW 'REBUILD' METHOD ***/
                slimSelect.rebuild();
            }
        },
        settings: {}
    });
});

kurthamilton avatar Sep 18 '24 20:09 kurthamilton