Base solution for your next web application
Open Closed

Dynamic Side bar Menu Issue #9940


User avatar
0
fawad29 created

What is your product version? 10 Latest

What is your product type (Angular or MVC)? ASP.net Core and Angular

What is product framework type (.net framework or .net core)? .NET5

What is ABP Framework version? The one that comes up with ASP.NET and Angular v10.

I am trying to use dynamic menu on the left hand side. I have searched your support side and tried to utilise what other people have done but I am struggling to implement it. This is what I have done so far:

Declared a global variable in app-navigation-service.ts.

myAppMenu: AppMenu = new AppMenu('MainMenu', 'MainMenu', []);

I am calling my web api to get the menu from the server in getMenu() function of app-navigation-service.ts

getMenu(): AppMenu {        
        this._myMenuService.getAllGrantedMenus(1, 1, 2)
            .subscribe(result => {
                console.log(result);                
                this.myAppMenu = result;                
                abp.event.trigger('myMenuLoaded', this.myAppMenu);

            });
        return this.myAppMenu;      
    }

In side-bar-menu.component.ts I am registering the event and your code is being used to call getMenu() function. The code is shown below.

ngOnInit() {
        this.menuLoaded();
        this.menu = this._appNavigationService.getMenu();

        this.currentRouteUrl = this.router.url.split(/[?#]/)[0];

        this.router.events
            .pipe(filter((event) => event instanceof NavigationEnd))
            .subscribe(
                (event) =>
                    (this.currentRouteUrl = this.router.url.split(/[?#]/)[0])
            );
    }
    
 menuLoaded(): void {
        abp.event.on('myMenuLoaded', function (menu) {            
            console.log("EVENT IS FIRED");
            console.log(menu);
            this.menu = menu;           
            
        });
    }

The above event is fired, but the menu is blank. I guess it is because the html and angular templates are executed before the menu data is returned. I am struggling to re-render the menu as it should be re-rendered when event is fired. Can you please help?


6 Answer(s)
  • User Avatar
    0
    musa.demir created

    The above event is fired, but the menu is blank.

    menuLoaded(): void {
            abp.event.on('myMenuLoaded', function (menu) {            
                console.log("EVENT IS FIRED");
                console.log(menu);
                this.menu = menu;           
                debugger; // Can you please add debugger here and check if `this.menu` defined here.
            });
        }
    

    If it is defined, you can add a ngIf in html side to wait for menu. side-bar-menu.component.html

    <!-- BEGIN: Aside Menu -->
    <div [class]="'aside-menu-wrapper aside-menu-' + currentTheme.baseSettings.menu.asideSkin" id="kt_aside_menu_wrapper" *ngIf="menu">
        <!----....---->
    </div>
    <!-- END: Aside Menu -->
    
  • User Avatar
    0
    fawad29 created

    @musa.demir Thank you for your reply.

    When I add *ngif="menu", I received the below error.

    `

    <div [class]="'aside-menu-wrapper aside-menu-' + currentTheme.baseSettings.menu.asideSkin" id="kt_aside_menu_wrapper" *ngif="menu"> 
        <div #asideMenu ktMenu [options]="menuOptions" [perfectScrollbar]="{wheelPropagation: false}"
             [ngStyle]="{'max-height': '90vh', 'position': 'relative'}" id="kt_aside_menu" class="aside-menu scroll"
             [attr.data-menu-vertical]="1" [attr.data-menu-scroll]="ui.getIsMenuScrollable() ? 1 : 0"
             [attr.data-menu-dropdown]="ui.isSubmenuToggleDropdown() ? 1 : 0" (mouseenter)="mouseEnter($event)"
             (mouseleave)="mouseLeave($event)" [class]="ui.getLeftAsideClass()">
            <ul class="menu-nav">
                <li class="menu-item mb-5" aria-haspopup="true"
                    data-ktmenu-submenu-toggle="hover" *ngIf="currentTheme.baseSettings.menu.searchActive">
                    <menu-search-bar></menu-search-bar>
                </li>
                <ng-container [ngTemplateOutlet]="menuListTemplate"></ng-container>
            </ul>
        </div>
    </div>
    
    <!-- END: Aside Menu -->`
    

    Yes, this.menu contains data when event is fired, please see below the console output.

    There must be a way of re-rendering menu.

  • User Avatar
    0
    fawad29 created

    Just an update, I was using ngif instead of ngIf (note capital I), after changing it to capital I, I don't receive error but menu is still not displayed, even though it contains the data. I don't know if menu is displayed this way after ngOnInit, there may be a different way of re-rendering i.e calling some method etc. I am not be sure though, can you think of anything else, as it seems like a common functionality?

  • User Avatar
    0
    fawad29 created

    I have fixed this issue, thanks to @musa.demir for asking me to use *ngIf. I am showing my implementation below so that it may help someone else if they get stuck.

    In side-bar-menu.component.html add *ngIf="menu", note capital I of If.

    <!-- BEGIN: Aside Menu -->
    <div [class]="'aside-menu-wrapper aside-menu-' + currentTheme.baseSettings.menu.asideSkin" id="kt_aside_menu_wrapper" *ngIf="menu">
        <div #asideMenu ktMenu [options]="menuOptions" [perfectScrollbar]="{wheelPropagation: false}"
            [ngStyle]="{'max-height': '90vh', 'position': 'relative'}" id="kt_aside_menu" class="aside-menu scroll"
            [attr.data-menu-vertical]="1" [attr.data-menu-scroll]="ui.getIsMenuScrollable() ? 1 : 0"
            [attr.data-menu-dropdown]="ui.isSubmenuToggleDropdown() ? 1 : 0" (mouseenter)="mouseEnter($event)"
            (mouseleave)="mouseLeave($event)" [class]="ui.getLeftAsideClass()">
            <ul class="menu-nav">
                <li  class="menu-item mb-5" aria-haspopup="true"
                    data-ktmenu-submenu-toggle="hover" *ngIf="currentTheme.baseSettings.menu.searchActive">
                    <menu-search-bar></menu-search-bar>
                </li>
                <ng-container [ngTemplateOutlet]="menuListTemplate"></ng-container>
            </ul>
        </div>
    </div>
    <!-- END: Aside Menu -->
    

    Replaced this.menu = this._appNavigationService.getMenu(); in ngOnInit() of side-bar-menu.component.ts with the code shown below. Replace your service and method names. Also, don't forget to inject your service in the constructor of side-bar-menu.component.ts

    this._myMenuService.getAllGrantedMenus(1, 1, 2)
                .subscribe(result => {
                    console.log(result);                
                    this.menu = result;                                
                });
    
  • User Avatar
    0
    fawad29 created

    Hi,

    The menu is loaded fine as per my previous comment, however, sometimes I need to progammatically refresh menu so that it gets the latest data from the server. What is the best way to refresh the menu?

    I tried to use events for this purpose but when event is triggered, my global function inside side-bar-menu.component.ts is not available inside the trigged code so I can't simply use the code below.

    loadMyMenu(myParameterForMenuSelection: number): void {
    //Code here for getting the menu from the server.
     }
    reloadMenu(): void {        
            abp.event.on('myParameterForMenuSelectionChanged', function (myParameterForMenuSelection) {
                console.log("EVENT IS FIRED");
                console.log(myParameterForMenuSelection);
                this.loadMyMenu(myParameterForMenuSelection);//I get error here that loadMyMenu is not a function
    
            });
        }
    

    I receive the below error when event is fired.

    ERROR TypeError: this.loadMyMenu is not a function

    What is the best way to refresh the menu?

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @learner29

    Using events is the way for handling such changes. Change your event definition like this;

    abp.event.on('myParameterForMenuSelectionChanged', () => (myParameterForMenuSelection) {
                console.log("EVENT IS FIRED");
                console.log(myParameterForMenuSelection);
                this.loadMyMenu(myParameterForMenuSelection);//I get error here that loadMyMenu is not a function
    });