themesberg / flowbite

Open-source UI component library and front-end development framework based on Tailwind CSS
https://flowbite.com
MIT License
7.6k stars 716 forks source link

How to call initModals from JS? #524

Closed RadekHavelka closed 10 months ago

RadekHavelka commented 1 year ago

In docs you mention

https://flowbite.com/docs/getting-started/introduction/#components

The initFlowbite function sets up all of the init functions for dropdowns, modals, navbars, tooltips and so on to hook onto the data attributes. Alternatively, you can also initialise each component category class separately with initDropdowns or initModals.

but there is no example how to use that in plain JS, not components. I am dynamically adding buttons that needs have tags to toggle modal (that is present in the code already) and need flowbite to re-detect these buttons and make the toggles work. I expect there is a simple function like the one mentioned initModals() that can do that, but I cannot seem to find it anywhere once the flowbite js code is loaded. Maybe its hidden in some namespace?

AndrMoura commented 1 year ago

I have encountered the same problem, wherein I have a page that contains multiple comments, each with a 'report' button that links to a singular report modal. Whenever I dynamically add new comments (using HTMX), these newly added report buttons do not have a listener to the report modal. Using the original initModals alone does not solve the issue as it also adds event listeners to buttons that already have existing listeners, causing event stacking (and massive performance issues). To address this issue, I have created my own initModals in JavaScript that adds event listeners to new content only. Additionally, I modified the source code to access the original Modal instance (that is created when the page loads), allowing me to tag the new comment's respective report button to the original report modal!

I would like to hear a devs opinion to address this type of issue.

RadekHavelka commented 1 year ago

as I purchased the PRO version of this code, I'd love to hear some feedback from the developer, because in current situation this is rather useless. Its not only problem of modals, its any case of "data-dropdown-toggle" or any other component bound like that. Bootstrap has this sorted out very nicely and I don't see a reason why this should not be working the same way.

zoltanszogyenyi commented 1 year ago

Hey @RadekHavelka,

Can you please give me an example of how you're trying to use it?

I'll need a reproduction to be able to provide a patch or feature update for this.

Cheers, Zoltan

RadekHavelka commented 1 year ago

I have HTML page that uses flowbite. After it loads, when user does a certain interaction, new HTML code is loaded via javascript fetch, and injected into page. If this code contains any "interactive" flowbite things like dropdowns, modals etc, they are NOT initialised and not working as expected, because (I believe) flowbite initialisation runs only once and I am not aware of any function to reinit it again (see my original post here about missing info in doc).

In bootstrap you would simply call something to do the init the newly added items, create listeners etc.

Would be enough to have such a call available in plain javascript (ie window.flowbite.init() or whatever), without the problems mentioned above (that it adds multiple listeners in case the elements were already initialised).

I suggest to add some data attribute or class to initialised elements and not reinit them again, this might do the magic.

I am aware I can do all the interactivity manually using javascript, but that looses advantage of this framework.

zoltanszogyenyi commented 1 year ago

Hey @RadekHavelka,

Thanks for the explanation - this should be an easy fix.

All we need to do is attach the initFlowbite() function to the window object for the general file.

You could technically also import flowbite via WebPacks (ESM or CJS) and then import initFlowbite from 'flowbite' and you could initialise the components programatically at any point in time based on your own codebase.

I'll look into this for sure for a new minor version.

Cheers, Zoltan

Edit: the init stacking is indeed something we'll have to also work on so we can keep an object of instances for the initialised components and skip them whenever the initFlowbite function is called again.

RadekHavelka commented 1 year ago

What I used to use in JQuery was that .live(click, ...) that used to work on any matching elements inserted now or in future, that was pretty handy. https://api.jquery.com/live/ its deprecated now, but might be useful for ideas

moshegutman commented 1 year ago

I’m pretty sure we need to use the MutationObserver to monitor changes to the DOM. This would solve Blazor compatibility too.

leandrodesouzadev commented 1 year ago

Is there any updates on this issue?

malikvogt commented 1 year ago

I have tried to implement a basic webpack setup for the assets in my Django project and replaced django-compressor.

In the main script I simply tested to initialize flowbite when an htmx request loads.

// Initialize Flowbite
import { initFlowbite } from 'flowbite';

htmx.onLoad(function() {
    initFlowbite();
});

This works, but is extremely slow and buggy when I scroll the page. (Not if I comment out the initFlowbite). Also, this initialization creates multiple modal-backdrops at the end of the body tag. This results in an ugly and unperformant UI.

Any recommendations or solutions?

zoltanszogyenyi commented 1 year ago

Hey everyone,

With the new release of v1.6.6 you should now be able to access all init functions including initFlowbite via the window object - I believe a part of the import problems should be addressed.

Regarding more advanced ways of initialising the event listeners we'll have to make a more comprehensive update that uses advanced verifications so we only init the newly added items to the DOM.

Cheers, Zoltan

msm1227 commented 11 months ago

I am having a similar issue and it may just boil down to me not knowing how to implement it.

I have a modal (with an id of "pro") that I would like to pop up after a certain amount of time and won't have a button on the page for it. How would I go about doing this?

Thanks!

zoltanszogyenyi commented 10 months ago

Hey everyone!

Flowbite v2.0 fixes this issue by bringing a brand new Instances Manager.

Please read more about it here:

https://flowbite.com/docs/getting-started/javascript/ https://github.com/themesberg/flowbite/releases/tag/v2.0.0

Cheers, Zoltan

Ifedi commented 6 months ago

I'm struggling frustratedly to see how this issue is "completed". It's all well to say you have solved the issue with "Instances Manager". Please, how difficult is it to present a simple example of how to initialize the interactivity of Modal, Dropdown, Drawer, etc whenever a new element bearing the flowbite data attributes is DYNAMICALLY ADDED to the page in vanilla JS?

I'm really confused since I'd assume that this is a very basic scenario that ought to be covered in a framework like this. Any suggestion for me to implement the details myself defeats the whole purpose of using a framework such as this in the first place!

georgekronberg commented 5 months ago

Same question, how do I use Instances Manager to make fix the problem with subsequence calls to initFlowbite creating additional bindings for existing already bound components?

zachbellay commented 4 months ago

Looks like @samld was kind enough to make a PR for changes to support this!

Would suggest showing your support to get it merged: https://github.com/themesberg/flowbite/pull/824