Dropdown Component Not Initializing correctly on Navigation with Angular RouterLink
ayoubkhial opened this issue · 0 comments
Describe the bug
When navigating between pages using Angular's routerLink
, the dropdown components powered by Flowbite do not initialize correctly on the new page unless a full browser reload is performed. This issue affects navigation from a login page to an admin page, both of which utilize Flowbite's dropdown component.
To Reproduce
- Start the Angular application with Flowbite dropdown components on the login and admin pages.
- Navigate from the login page to the admin page using routerLink.
- Observe that the dropdown on the admin page does not function.
Reload the browser on the admin page; the dropdown now works as expected.
Expected behavior
The dropdown components should initialize and function correctly after navigation between pages without requiring a browser reload.
Desktop (please complete the following information):
- OS: MacOS
- Browser: Google Chrome
- Version: 123.0.6312.122
Additional context
Currently, I am initializing Flowbite on every NavigationEnd
event by subscribing to router events in the ngOnInit
lifecycle hook of the app.component.ts.
ngOnInit() {
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
initFlowbite();
}
});
}
Alternatively, a directive is used specifically on components where Flowbite is utilized to manage the initialization, ensuring that elements are properly recognized and initialized by Flowbite post-navigation. (source)
import { initFlowbite } from 'flowbite';
import { Subject, concatMap, delay, of } from 'rxjs';
const flowbiteQueue = new Subject<() => void>();
flowbiteQueue.pipe(concatMap((item) => of(item).pipe(delay(100)))).subscribe((x) => {
x();
});
export function Flowbite() {
return function (target: any) {
const originalOnInit = target.prototype.ngOnInit;
target.prototype.ngOnInit = function () {
if (originalOnInit) {
originalOnInit.apply(this);
}
initFlowbiteFix();
};
};
}
export function initFlowbiteFix() {
flowbiteQueue.next(() => {
const elements = Array.from(document.querySelectorAll('*'));
const flowbiteElements: Element[] = [];
const initializedElements = Array.from(document.querySelectorAll('[flowbite-initialized]'));
for (const element of elements) {
const attributes = Array.from(element.attributes);
for (const attribute of attributes) {
if (attribute.name.startsWith('data-') && !initializedElements.includes(element)) {
flowbiteElements.push(element);
break;
}
}
}
for (const element of flowbiteElements) {
element.setAttribute('flowbite-initialized', '');
}
initFlowbite();
for (const element of flowbiteElements) {
const attributes: { name: string; value: string }[] = Array.from(element.attributes);
const dataAttributes = attributes.filter((attribute) => attribute.name.startsWith('data-'));
for (const attribute of dataAttributes) {
element.setAttribute(attribute.name.replace('data-', 'fb-'), attribute.value);
element.removeAttribute(attribute.name);
}
}
});
}