brianvoe / slim-select

Slim advanced select dropdown
http://slimselectjs.com
MIT License
1.07k stars 200 forks source link

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

Open kurthamilton opened 2 months ago

kurthamilton commented 2 months ago

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: {}
    });
});
brianvoe commented 2 months ago

Thank you for your submission.

Most likely if anything I would return a second value to afterChange some sort of difference value.

If you want to put together a pr Ill get it in.

Thanks.

kurthamilton commented 2 months ago

Thanks @brianvoe. I'll look at putting something together. I have another feature request / idea as well. Is it always best to open an issue first?

brianvoe commented 2 months ago

ya maybe figuring out what your trying to do and making sure it make sense before submitting a pr might be best.

But also I have merged in people's stuff and all they did was submit a pr