After I customize the user menu, it fails to open, I'm getting a console error: ERROR TypeError: Cannot read properties of undefined (reading 'toggle')
This is the code I'm using:
function userMenuFactory(userMenu: UserMenuService, routes: RoutesService, router: Router) {
return () => {
try {
// Defensive check to ensure userMenu service is available
if (!userMenu) {
console.warn('UserMenuService is not available, skipping menu configuration');
return;
}
<br>
userMenu.patchItem(eUserMenuItems.MyAccount, {
action: () => {
const { path } = routes.find(item => item.name === eAccountRouteNames.ManageProfile);
router.navigateByUrl(path);
},
});
<br>
// Remove unwanted menu items with individual error handling
const itemsToRemove = [
eUserMenuItems.LinkedAccounts,
eUserMenuItems.AuthorityDelegation,
eUserMenuItems.ExternalLogins,
eUserMenuItems.SecurityLogs,
eUserMenuItems.Sessions
];
<br>
itemsToRemove.forEach(item => {
userMenu.removeItem(item);
});
<br>
} catch (error) {
console.error('Error configuring user menu:', error);
}
}
}
Using an app initializer
provideAppInitializer(() => {
const initializerFn = (userMenuFactory)(inject(UserMenuService), inject(RoutesService), inject(Router));
return initializerFn();
}),
I also tried doing it in the app.component constructor and OnInit, same results.
This only happens after login, If I refresh the page after I'm logged in, it works, but users are not expected to refresh the page.
16 Answer(s)
-
0
To properly customize the user menu in ABP Angular and avoid issues like "Cannot read properties of undefined (reading 'toggle')" after login, you should ensure that your user menu modifications are performed after the menu is fully initialized and the user is authenticated. The error typically occurs if the menu or its dependencies are not ready when you attempt to patch or remove items, especially right after login when the application state is still being established.
Here is the recommended approach:
Use Angular Lifecycle and Observables
Instead of running your customization in an app initializer or constructor, subscribe to the authentication/user state and perform menu modifications only when the user is authenticated and the menu is available.Example Implementation
Place this logic in your main component (e.g.,app.component.ts
) insidengOnInit
:
import { Component, OnInit } from '@angular/core'; import { UserMenuService, eUserMenuItems } from '@abp/ng.theme.shared'; import { RoutesService } from '@abp/ng.core'; import { Router } from '@angular/router'; import { ConfigStateService } from '@abp/ng.core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent implements OnInit { constructor( private userMenu: UserMenuService, private routes: RoutesService, private router: Router, private configState: ConfigStateService ) {} ngOnInit(): void { this.configState.getOne$('currentUser').subscribe(currentUser => { if (currentUser?.isAuthenticated) { // Patch MyAccount action this.userMenu.patchItem(eUserMenuItems.MyAccount, { action: () => { const { path } = this.routes.find(item => item.name === 'AbpAccount::ManageProfile'); this.router.navigateByUrl(path); }, }); // Remove unwanted items [ eUserMenuItems.LinkedAccounts, eUserMenuItems.AuthorityDelegation, eUserMenuItems.ExternalLogins, eUserMenuItems.SecurityLogs, eUserMenuItems.Sessions ].forEach(item => this.userMenu.removeItem(item)); } }); } }
Why This Works
- The code waits for the user to be authenticated and the menu to be initialized before making changes.
- This prevents errors related to undefined menu items or missing DOM elements.
- It also ensures the menu is always in sync with the current user state, even after login without a page refresh.
Do Not Use App Initializer for Menu Customization
App initializers run before the application is fully bootstrapped and before user/menu state is available, which can cause the issues you observed.Reference
Official ABP documentation recommends using theUserMenuService
in a component after authentication for menu customization.
Sources:
- https://abp.io/docs/latest/framework/ui/angular/theming
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
-
0
I've already tried what the AI is suggesting, still doesn't work. I need to resolve this ASAP. Thanks.
-
0
I think the issue is not because of the customizations, I removed them and the menu is still not being displayed. This is now an urgent matter for us, it is in production. It started happening after the upgrade to 9.2
-
0
-
0
Hello,
I can suggest you to override the default navigation to the manage profile page as I mentioned here previously https://abp.io/qa/questions/9674/3a1b61b3-1e0a-ab46-a3ae-8dd97adc6a0d
@NgModule({ providers: [ { provide: NAVIGATE_TO_MANAGE_PROFILE, useFactory: navigateToManageProfileFactory, }, ], }) export class AppModule {} export function navigateToManageProfileFactory() { const windowService = inject(AbpWindowService); const routes = inject(RoutesService); return () => { const { path } = routes.find(item => item.name === eAccountRouteNames.ManageProfile); windowService.open(path, 'self'); }; }
You will also need to update the patch in your component as follows
@Component({ standalone: false, selector: 'app-root', template: ` <abp-loader-bar></abp-loader-bar> <abp-dynamic-layout></abp-dynamic-layout> <abp-gdpr-cookie-consent></abp-gdpr-cookie-consent> `, }) export class AppComponent implements OnInit { private userMenu = inject(UserMenuService); private configState = inject(ConfigStateService); ngOnInit(): void { this.configState.getOne$('currentUser').subscribe(currentUser => { if (currentUser?.isAuthenticated) { // Patch MyAccount action // ⚠️ remove this part and just use the new provider override here // this.userMenu.patchItem(eUserMenuItems.MyAccount, { // action: () => { // const { path } = this.routes.find(item => item.name === 'AbpAccount::ManageProfile'); // this.router.navigateByUrl(path); // }, // }); // Remove unwanted items [ eUserMenuItems.LinkedAccounts, eUserMenuItems.AuthorityDelegation, eUserMenuItems.ExternalLogins, eUserMenuItems.SecurityLogs, eUserMenuItems.Sessions, ].forEach(item => this.userMenu.removeItem(item)); } }); } }
Another issue I'm seeing is that the main menu is not collapsing when I select a different menu item, and the scroll bar is gone, If I expand some items I lose visibility and can't scroll down.
The problem you mentioned on the sidebar was solved in the previous version https://github.com/abpframework/abp/issues/22301 If you could provide the version for your
@volosoft/abp.ng.theme.lepton-x
package, I can assist further.You can let me know if you need further assistance. Thank you for your cooperation.
-
0
-
0
-
0
Here's a video of the issues:
https://app.screencast.com/Xw2IVEfeal1jV
-
0
Any updates
-
0
Hello again,
Thank you for providing extra details on your problem.
If the approach I suggested above does not solve your problem, that would be the best if you could provide a minimal reproducible example so that I could assist you further. Here is my e-mail address: sumeyye.kurtulus@volosoft.com
I have also checked the version details, and the sidebar problem should not occur in this version.
-
0
The sidebar issue is solved, but the user context menu is still not opening when I use a subdomain; if I log in as the host, it's fine. I created a solution from scratch, and I can confirm the behaviour.
Is it possible to schedule a Zoom or Teams session to troubleshoot this? I've been struggling for quite some time now, and I need to fix it; it is in production.
Another option would be to replace the component, but I'm not sure which one is it, I tried eThemeLeptonXComponents.CurrentUser, but seems not to be working.
-
0
The sidebar issue is solved, but the user context menu is still not opening when I use a subdomain; if I log in as the host, it's fine. I created a solution from scratch, and I can confirm the behaviour.
Hello again, Thank you for responding and confirming that the sidebar problem does not persist. Also, that would be the best if you could send the solution you created from scratch so that I could help further beforehand. Here is my e-mail address: sumeyye.kurtulus@volosoft.com.
Another option would be to replace the component, but I'm not sure which one is it, I tried eThemeLeptonXComponents.CurrentUser, but seems not to be working.
Yes, this is the correct replacement key, however you would not need such replacement for this case.
-
0
Like I said, I just created a solution from scratch using ABP Studio. You need to use a subdomain for the issue to be noticed. Logging in as host works fine, but logging in using a subdomain for the tenant doesn't.
I made no modifications to the solution, so you should be able to do the same.
-
0
Hello again,
Thank you for providing extra details about your problem. We will be looking into this issue for the next patch release. Until we publish a solution, could you try this approach to eliminate the error temporarily?
// app.component.ts export class AppComponent implements OnInit { private userMenu = inject(UserMenuService); private configState = inject(ConfigStateService); protected session = inject(SessionStateService); protected windowService = inject(AbpWindowService); protected readonly localStorageService = inject(AbpLocalStorageService); ngOnInit(): void { const tenant = this.session.getTenant().id || null; this.configState.getOne$('currentUser').subscribe(currentUser => { if (currentUser?.isAuthenticated) { // One-time reload when user is authenticated and has tenant if (tenant && !this.localStorageService.getItem('reloadForTenant')) { this.localStorageService.setItem('reloadForTenant', 'true'); this.windowService.reloadPage(); } [ eUserMenuItems.LinkedAccounts, eUserMenuItems.AuthorityDelegation, eUserMenuItems.ExternalLogins, eUserMenuItems.SecurityLogs, eUserMenuItems.Sessions, ].forEach(item => this.userMenu.removeItem(item)); } else { this.localStorageService.removeItem('reloadForTenant'); } }); } }
Thank you for your cooperation.
-
0
Yes, that was my workaround, but customers complained about the user experience. I created my own toolbar using the ng-bootstrap dropdown component for the user profile menu and replaced the component; it works now.
For the sidebar issue, I had to first include the ng-bundle from the node_modules and then the one compiled from the SCSS source code that has some minor modifications to get it to work. Also, is there an updated guide on how to customize lepton-x from the source, or a better way to do it? The build has a lot of warnings, but it produces an output.
{ "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/ng-bundle.css", "inject": false, "bundleName": "ng-bundle" }, { "input": "src/assets/css/pro/libraries/ng-bundle.css", "inject": false, "bundleName": "ng-bundle" },
-
0
Thank you for the response. We will be looking into this problem and propose a solution as soon as possible. You can check the releases for this https://github.com/abpframework/abp/releases
Also, is there an updated guide on how to customize lepton-x from the source, or a better way to do it? The build has a lot of warnings, but it produces an output.
If you need to get the source code for your project, you can use this command under your angular directory
abp add-package @volosoft/abp.ng.theme.lepton-x --with-source-code
Thank you for your cooperation.