htmlstreamofficial / preline

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
https://preline.co
Other
4.84k stars 306 forks source link

Dynamically Change the Options in Advanced Select #183

Closed more-malekpour closed 10 months ago

more-malekpour commented 11 months ago

Hello,

First of all, thanks for this awesome library. I'm trying to dynamically change (add and remove) the options of the advanced select but have had no luck so far with the HSSelect methods, such as buildOption(). I can easily create/remove options for vanilla HTML with JS, but not working for the Advanced Select plugin.

Thanks in advance for your assistance.

kshitijmehta commented 11 months ago

Was just looking for the same thing. I'm having issues even to render dynamic options for Advanced Select.

My code is pretty simple.

          <select
            data-hs-select='{// all the config from the Country selector from the example }'
            className="hidden">
           // loading the options dynamically. 
            {
              namespaces.map((namespace) => {
                return (
                  <option value={namespace.metadata.uuid} key={namespace.metadata.uuid}>
                    {namespace.metadata.name}
                  </option>
                )
              })
            }

          </select>

Nothing gets rendered

sebastianbilling commented 11 months ago

I'm able to render dynamic options for Advanced Select: ` <select className="hidden"

<option value={""}> Choose {items(item => { return (

) })} `

However, I'm unable to use the onChange to set the state, any know know why?

Are you sure you imported the PrelineScript according to the documentation?

more-malekpour commented 11 months ago

@sebastianbilling For the first render, I can render options with a similar code to yours. The problem is updating (adding or removing) options with jQuery or vanilla JS. Let's say I want to update the options of a select based on data retrieved from the server through JSON object.

olegpix commented 11 months ago

@sebastianbilling For the first render, I can render options with a similar code to yours. The problem is updating (adding or removing) options with jQuery or vanilla JS. Let's say I want to update the options of a select based on data retrieved from the server through JSON object.

Are you using any library or framework like Vue or React? Have you tried updating your select using a helper function? E.g.

const [options, setOptions] = useState(['one', 'two']);

// yours options update code

useEffect(() => {
    HSStaticMethods.autoInit(['select']);
}, [options]);
more-malekpour commented 11 months ago

@sebastianbilling For the first render, I can render options with a similar code to yours. The problem is updating (adding or removing) options with jQuery or vanilla JS. Let's say I want to update the options of a select based on data retrieved from the server through JSON object.

Are you using any library or framework like Vue or React? Have you tried updating your select using a helper function? E.g.

const [options, setOptions] = useState(['one', 'two']);

// yours options update code

useEffect(() => {
    HSStaticMethods.autoInit(['select']);
}, [options]);

@olegpix Thanks for your answer. I'm using Django (Python), thus I have to stick with jQuery and vanilla JS for updating the options. I tried to replicate your suggested code but unfortunately couldn't translate it to a working jQuery code.

olegpix commented 11 months ago

@sebastianbilling For the first render, I can render options with a similar code to yours. The problem is updating (adding or removing) options with jQuery or vanilla JS. Let's say I want to update the options of a select based on data retrieved from the server through JSON object.

Are you using any library or framework like Vue or React? Have you tried updating your select using a helper function? E.g.

const [options, setOptions] = useState(['one', 'two']);

// yours options update code

useEffect(() => {
    HSStaticMethods.autoInit(['select']);
}, [options]);

@olegpix Thanks for your answer. I'm using Django (Python), thus I have to stick with jQuery and vanilla JS for updating the options. I tried to replicate your suggested code but unfortunately couldn't translate it to a working jQuery code.

Hmmm... The code is very similar to React, which is why I thought you were using it. In any case, if you are using vanilla code (without a library), this means that you need to reinitialize the select using this method HSStaticMethods.autoInit(['select']); after you update options , perhaps it will be a callback to the fetch function. The basic idea here is that you need to reinitialize the select after some update.

const data = await fetch('https://api.com/items').then(() => {
    HSStaticMethods.autoInit(['select']);
});

or

const data = await fetch('https://api.com/items').then(() => {
    setTimeout(() => {
        HSStaticMethods.autoInit(['select']);
    }, 100);
});

Hope it helps.

more-malekpour commented 11 months ago

I really appreciate your help. I did the following steps but still nothing happened in the frontend:

  1. Replaced the old options with the new options with:
    $("select").empty().append("<option value='test'>test</option>")
  2. In the next step, I used HSStaticMethods.autoInit(["select"])

Thanks in advance.

shanke-pvex commented 11 months ago

I have the same problem. Adding options dynamically to the advanced select, nothing happens in frontend. No success with HSStaticMethods.autoInit(["select"]). If i add options to a normal select via reactive data in vue3 it works. Is it possible to rerender the advanced select?

shanke-pvex commented 11 months ago

If i call this: new HSSelect(document.querySelector("#module_type")); before my axios request and once in success handler i get the following ui.

Bildschirmfoto 2023-12-04 um 22 11 58

The select seems to bo twice initalized.

I hope someone can help with this problem.

umaraziz0 commented 10 months ago

Having the same problem and unable to update the options dynamically. One workaround is to not render the component until the options data is fetched, which isn't very ideal.

Hope there will be a fix for this soon.

more-malekpour commented 10 months ago

It seems that this issue is a bug rather than help wanted, could you please reconsider the label? @jahaganiev Thank you

jahaganiev commented 10 months ago

Hey @more-malekpour, updated the label - our team is looking into it. Thanks!

jahaganiev commented 10 months ago

Hey everyone, we've just released v2.0.3 update with dynamic validation states, the ability to add/remove options and more. Check out some sample demos at https://preline.co/docs/advanced-select.html#dynamic-validation-states

After updating, if you are still having any issues, please open a new issue with more details. Thanks!

marconi commented 9 months ago

I have the same issue even after updating to latest, the select plugin just doesn't detect changes on the select element's options. I had to call destroy() first then re-instantiate the plugin with new HSSelect(...). The component ends up flickering which looks really bad but its the only way for me for now.

SwpOlavio commented 3 months ago

"I managed to update the advanced select in the modal and vue 3."

<div>
                                    <label for="role" class="block text-sm font-semibold mb-2 dark:text-gray-400">Role</label>
                                    <div class="relative">
                                        <!-- Select -->
                                        <select  ref="selectRole" v-model="form.role" :data-hs-select="JSON.stringify(currentOptions)" class="hidden">
                                            <option  v-for="(name, id ) in roleOptions" :key="id" :value="name">
                                                {{name}}
                                            </option>

                                        </select>
                                        <!-- End Select -->
                                    </div>
                                    <p v-if="form.errors.role" class=" text-sm text-red-500 mt-2" id="role-error">{{form.errors.role}}</p>
                                </div>

const props = defineProps({
    roleOptions: Object,
})
const currentOptions = {
    searchWrapperClasses: "bg-white p-2 -mx-1 sticky top-0 dark:bg-swp-input-bg",
    placeholder: "Select",
    toggleTag: "<button type=\"button\"><span class=\"me-2\" data-icon></span><span class=\"text-gray-800 dark:text-gray-200\" data-title></span></button>",
    toggleClasses: "hs-select-disabled:pointer-events-none hs-select-disabled:opacity-50 relative py-3 px-4 pe-9 flex text-nowrap w-full cursor-pointer bg-white border border-gray-200 rounded-lg text-start text-sm focus:border-blue-500 focus:ring-blue-500 before:absolute before:inset-0 before:z-[1] dark:bg-swp-input-bg dark:border dark:hover:border-blue-600 dark:border-gray-700 dark:text-gray-400",
    dropdownClasses: "mt-2 max-h-52 pb-1 px-1 space-y-0.5 z-20 w-full bg-white border border-gray-200 rounded-lg overflow-hidden overflow-y-auto [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-gray-300 dark:[&::-webkit-scrollbar-track]:bg-gray-700 dark:[&::-webkit-scrollbar-thumb]:bg-gray-500 dark:bg-swp-modal-bg dark:border-gray-700",
    optionClasses: "py-2 px-4 w-full text-sm text-gray-800 cursor-pointer hover:bg-gray-100 rounded-lg focus:outline-none focus:bg-gray-100 dark:bg-swp-modal-bg dark:hover:bg-swp-link-hover_color dark:text-gray-200 dark:focus:bg-gray-800",
    optionTemplate: "<div class=\"flex justify-between items-center w-full\"><span data-title></span><span class=\"hidden hs-selected:block\"><svg class=\"flex-shrink-0 size-3.5 text-blue-600 dark:text-blue-500\" xmlns=\"http:.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg></span></div>",
    extraMarkup: "<div class=\"absolute top-1/2 end-3 -translate-y-1/2\"><svg class=\"flex-shrink-0 size-3.5 text-gray-500 dark:text-gray-300\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m7 15 5 5 5-5\"/><path d=\"m7 9 5-5 5 5\"/></svg></div>"
};

const selectRole = ref(null)
const refreshSelect = () => {
    if (selectRole.value){
        window.HSSelect.getInstance(selectRole.value).destroy()
        nextTick(() => {
            new window.HSSelect(selectFuncao.value, currentOptions)
        })
    }
}
function openEditModal(_user) {
    form.role = _user.role
    refreshSelect()
    window.HSOverlay.open('#swp-modal')
}