Could you please tell me how to save the menu state when pressing F5? I’m not sure if I’m being clear. There’s an example on the Binance website. For instance, you click on the Sell NFT's
submenu, then you press F5, and despite the refresh, the menu state remains on Sell NFT's
.
Here is the URL Binance
I would like to obtain the same result with my web application.
If I click on ‘Dealing’
I have two subcategories (Dealing Overview & Order Authorization)
if I click on ‘Dealing Overview’ and then press F5, it returns to the initial state.
I would like to stay on Dealing Overview & Order Authorization
.
I really don’t know how to achieve this.
Here are 2 console logs:
1/ Here, I correctly retrieve the 13 categories.
2/ When I click on a subcategory, it displays correctly.
My problem is the following: Why does pressing F5 reset the menu state to 0? Do you have any ideas on how to solve this issue, please?
Here is my code
export class OnlineComponent implements OnInit {
private unsubscribe$ = new Subject<void>();
@Select((state: { app: AppStateModel }) => state.app.idleEvent)
idleEvent$: Observable<number>;
idleEventValue: number = 0;
private idleEventSubscription: Subscription;
faChevronRight = faChevronRight;
faChevronLeft = faChevronLeft;
faBars = faBars;
faSignOut = faSignOut;
faGear = faGear;
faBack = faChevronCircleLeft;
showElement: boolean = true;
showMenu: boolean = false;
showSideBar: boolean = false;
moduleLoading: boolean;
lastCheck;
title = this.cfg.APP_NAME;
readonly AUTO_LOGOFF_TIMEOUT: number = 525;
readonly AUTO_LOGOFF_COUNTDOWN: number = 60;
private modalRef?: BsModalRef;
selectedItem: IMenuItem;
nav: IMenuItem[] = [];
subMenu: IChildItem[] = [];
constructor(
public LS: LocalStoreService,
public SS: SessionStoreService,
public api: DataLayerService,
public share: DataShareService,
private router: Router,
public auth: AuthService,
public navService: NavigationService,
public cfg: AppConfig,
private autoLogOff: Idle,
private modalService: BsModalService,
private store: Store,
public _router: Router,
public _location: Location
) {}
ngOnInit() {
// Check if a "transaction" item exists in session storage.
if (this.SS.getItem("transaction") !== null) {
// If it exists, load navigation bar data.
this.navBarData();
} else {
// If not, redirect to the sign-in page.
this.router.navigateByUrl("/sessions/signin");
}
// Subscribe to route changes and log when a route is activated.
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe((routeChange: NavigationEnd) => {
const activatedRoute = this.router.routerState.root;
const activatedRouteSnapshot = this.getLastChild(activatedRoute);
if (activatedRouteSnapshot && activatedRouteSnapshot.routeConfig) {
// Get the activated route's name/path and log it.
const routeName = activatedRouteSnapshot.routeConfig.path;
console.log(`Route "${routeName}" is activated!`);
}
});
}
updateSidebar() {
// Check if the device is in mobile mode using the Utils.isMobile() function.
if (Utils.isMobile()) {
// If it's a mobile device, hide the sidebar.
this.showSideBar = false;
} else {
// If it's not a mobile device, show the sidebar.
this.showSideBar = true;
}
}
navBarData(): void {
// Update the sidebar based on the current device.
this.updateSidebar();
// Close sidenav on route change
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe((routeChange) => {
// Close the sidebar on route change if it's a mobile device.
if (Utils.isMobile()) {
this.showSideBar = false;
}
});
// Subscribe to menu items from the navigation service.
if (this.navService.menuItems$) {
this.navService.menuItems$.subscribe((items) => {
this.nav = items;
this.nav.forEach((item) => {
item.active = false; // Ensure all top-level items are initially inactive.
});
// Call the setActiveFlag() method if needed.
// this.setActiveFlag();
});
// Select the first item if there are items available.
if (this.nav.length > 0) {
this.selectItem(this.nav[0]);
}
}
}
// Helper function to get the last activated route.
getLastChild(route: ActivatedRoute): ActivatedRoute {
let lastChild = route;
while (lastChild.firstChild) {
lastChild = lastChild.firstChild;
}
return lastChild;
}
// Method to select a menu item.
selectItem(item) {
if (this.selectedItem === item) {
this.showElement = true;
} else {
// Set the 'active' state of each main menu item.
this.nav.forEach((i) => {
i.active = i === item;
});
this.selectedItem = item;
// Set the active main item and related properties.
this.setActiveMainItem(item);
// Log the updated state of main menu items.
console.log("Main Menu Items (after selection):", this.nav);
// Log the clicked menu item.
console.log("Clicked menu item:", item.name);
}
}
// Method to close the child navigation.
closeChildNav() {
// Set the child navigation state to closed.
this.navService.sidebarState.childnavOpen = false;
// Hide the main content element.
this.showElement = false;
// Show the main menu.
this.showMenu = true;
}
// Method to set the active main item and related properties.
setActiveMainItem(item) {
// Loop through each item in the main navigation.
this.nav.forEach((i) => {
// Set the 'active' state of the current item based on whether it matches the selected item.
i.active = i === item;
});
// Toggle the 'showElement' property to control whether the main content element is shown.
this.showElement = !this.showElement;
// Toggle the 'showMenu' property to control whether the main menu is shown.
this.showMenu = !this.showMenu;
// Set the 'subMenu' property to the sub-menu of the selected item, if it exists.
this.subMenu = item.sub;
}
// Method to change the active flag on click.
onClickChangeActiveFlag(item) {
// Call the setActiveMainItem method to update the active state and related properties.
this.setActiveMainItem(item);
}
// Method to toggle the sidebar visibility.
toggleSidebar() {
// Toggle the value of showSideBar to either show or hide the sidebar.
this.showSideBar = !this.showSideBar;
}
template
<div class="menu-content" [ngClass]="{ 'show-elem': !showElement, 'noshow-elem': showElement }">
<ul class="menu-items">
<li class="item" [ngClass]="{ active: item.active }" *ngFor="let item of nav">
<div class="menu-item" [ngClass]="{ 'show-menu': showMenu, 'noshow-menu': !showMenu }">
<span class="title" (click)="onClickChangeActiveFlag(item)">
<span>{{ item.name }}</span>
<fa-icon [icon]="faChevronRight"></fa-icon>
</span>
</div>
</li>
</ul>
</div>
<div [ngClass]="{ 'show-elem': showElement, 'noshow-elem': !showElement }">
<ul class="submenu-title">
<span class="title-sub" (click)="closeChildNav()">
<fa-icon [icon]="faChevronLeft"></fa-icon>
<span class="ml-2 btnBack">Retour</span>
</span>
<li class="items" routerLink="{{ subItem.state }}" *ngFor="let subItem of subMenu">
<span>{{subItem.name}}</span>
</li>
</ul>
</div>
2
Answers
Usually to handle this situation, websites rely either on the slug or the query currently held in the url. In the case of Binance that you mentioned, you can notice the
#199
in the query that is used to achieve the selection effect in the side menu (try changing it to 198 and notice another item will be selected).So in your case, you should rely on your route (for example checking if the value is
demandeOrdres
and highlight the corresponding item) or add a value in your url query that holds the value of the selected item.As @Mentlegen suggested, url params would be the efficient solution if you’re ok with exposing the params in url. Although I see no reason not to expose them, if for any reason you don’t wish to expose them – you can create a service with an observable returning an object that will keep the latest state of the menu, then subscribe to it in your component’s onInit, and update it each time user interacts with the menu.