I'm using angular 13, and i have to load a menu dynamically from Database so i have a function doing that name's loadMenu() , and i have to put the sidebare (where i have to put the menu loaded) in MetisMenu, but the problem is MetisMenu didn't work correcly without settimeout()
this is component.ts :
ngOnInit(): void {
this.LoadMenu();
const desktopMedium = window.matchMedia('(min-width:992px) and (max-width: 1199px)');
desktopMedium.addEventListener('change', () => {
this.iconSidebar;
});
this.iconSidebar(desktopMedium);}
LoadMenu() {
if (this.sessionManager.context != null) {
let args = new ParamsModel();
this.genericService.GetMenuGauche(args).subscribe(
data => {
this._menu = data;
this.GoToFirstNavigableMenuItem();
},
error => {
console.log(error);
}
);
}}
ngAfterViewInit() {
// activate menu item
setTimeout(() => {
new MetisMenu(this.sidebarMenu.nativeElement);
this._activateMenuDropdown();
}, 1000);}
CodePudding user response:
Explaining what's happening: The problem is that LoadMenu() is asynchronous.
So when you try activate MetisMenu, menu's data doesn't even exists yet. When you setTimeout by 1000ms, the asyncrounous function has enought time to end its process. That's why it works.
You should do it like so:
ngOnInit() {
if (this.sessionManager.context != null) {
let args = new ParamsModel();
this.genericService.GetMenuGauche(args).subscribe(data => {
this._menu = data;
this.GoToFirstNavigableMenuItem();
new MetisMenu(this.sidebarMenu.nativeElement);
this._activateMenuDropdown();
const desktopMedium = window.matchMedia('(min-width:992px) and (max-width: 1199px)');
desktopMedium.addEventListener('change', () => {
this.iconSidebar;
});
this.iconSidebar(desktopMedium);
},
error => {
console.log(error);
});
}
}
CodePudding user response:
I see you are working on the observable type which can help a lot. SetTimeout works because the code is asynchronous, so if you execute it continuously, the data isn't there yet. But the Observable type has a function where you can execute your code and what you want to do at the end you should put in your subscription method. This ensures that what is in the subscription will not be executed last until the operation in the pipe function is completed. In order to be able to put the code in the pipe function, you must additionally use the RxJS operator, which will allow you to do this. If you do not need to perform heavy operations, e.g. with data formatting, the tap operator will suffice.
I recommend that you familiarize yourself with the most popular operators of the RxJS library because they make writing the code much easier :)
Below is an example of use:
ngOnInit(): void {
if (this.sessionManager.context != null) {
let args = new ParamsModel();
this.genericService
.GetMenuGauche(args)
.pipe(
tap((data) => {
this._menu = data;
this.GoToFirstNavigableMenuItem();
})
)
.subscribe(
() => {
new MetisMenu(this.sidebarMenu.nativeElement);
this._activateMenuDropdown();
},
(error) => console.log(error)
);
}
}