Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Left panel menu items maximises and minimises on page reload and menu selection #1347

Open
ashwanikumar415 opened this issue Jun 13, 2017 · 6 comments

Comments

@ashwanikumar415
Copy link

Left panel menu minimises and maximises always for a fraction of second every time when page is refreshed or any menu item is selected
plunkr : http://plnkr.co/edit/yTMTofsjfw4XT4EOzint?p=preview

Note: To see issue occuring (especially page refresh case) download the zip from plunkr and run the index.html page individually
GIF :

leftpanel_min_max_issue

Expected behavior: Only already opened menu item should remain open with no flickering

Actual behavior: 8/10 times flicker happens, gets worse when the menu list is lengthy

@ashwanikumar415 ashwanikumar415 changed the title Left panel menu items maximises and minimises on page reload Left panel menu items maximises and minimises on page reload and menu selection Jun 20, 2017
@freemember007
Copy link

how about this issue? i undergo a same question.

@ashwanikumar415
Copy link
Author

ashwanikumar415 commented Jul 7, 2017

Resolved this issue by writing a decorator for directive maMenubar (https://github.com/marmelab/ng-admin/blob/master/src/javascripts/ng-admin/Main/component/directive/maMenuBar.js)

If you observe in maMenubar.js, whenever "locationChangeSuccess" event is fired render() is invoked which causes the whole left menu to be redrawn again. That causes the flicker.
So one of the fixes could be calling
a method like updateLeftMenuStyling() which would just highlight the activeMenu item and close the other menu items (if at all some of them are opened) using javascript instead of render(). like below
`var listener = $rootScope.$on('$locationChangeSuccess', function() {

        scope.path = $location.path();
        updateLeftMenuStyling(activeMenu, activeParentMenu);
        //render();
    });`

    function updateLeftMenuStyling(menu, parentMenu) {
      var elements = getElementsForMenu(menu);
      elements.allUlElements.addClass('collapsed');
      elements.allArrowElements.removeClass('glyphicon-menu-down');
      elements.allArrowElements.addClass('glyphicon-menu-right');
      if (parentMenu) {
        openMenu(parentMenu);
      }
      elements.allAnchorTags.removeClass('active');
      if(menu.link()) { 
        elements.anchorTag.addClass('active');
      }
      elements.anchorTag.blur();
    }

  function getElementsForMenu(menu) {
    let parentLi;
    angular.forEach(element.find('li'), function(li) {
        const liElement = angular.element(li);
        if (liElement.attr('data-menu-id')  === (menu.uuid).toString()) {
            parentLi = liElement;
        }
    });
    const anchorTag = (parentLi) ? parentLi.find('a')[0] : null;
    const ulElements = (parentLi) ? parentLi.find('ul') : null;
    const arrowElement = (anchorTag) ? anchorTag.getElementsByClassName('arrow')[0] : {};
    return {
      arrow: angular.element(arrowElement),
      allArrowElements: angular.element(element.find('span.arrow')),
      ul: (ulElements) ? ulElements.eq(0) : {},
      anchorTag: angular.element(anchorTag),
      allAnchorTags: angular.element(element.find('a')),
      allUlElements: angular.element(element.find('ul'))
    };
  }`
  • Modified getElementsForMenu() to return some more elements like shown above.
  • Modified scope.activateLink a bit to know activeMenu, activeParentMenu (passed as argument in updateLeftMenuStyling)

` scope.activateLink = function (menu, parentMenu) {

        activeMenu = menu;
        activeParentMenu = (parentMenu) ? parentMenu : null;
        if (!menu.link()) {
            return;
        }
        if (menu.autoClose()) {
            openMenus = [];
        }
    };`
  • Now instead of using '/view/menuBar.html ' in your decorator , modify this html a bit and use that instead (just to get that parentMenu argument in scope.activateLink)
<div class="navbar-default sidebar" role="navigation" compile="menu.template()">
    <div class="sidebar-nav navbar-collapse collapse" uib-collapse="$parent.isCollapsed">
        <ul class="nav" id="side-menu">
            <li class="entities-repeat" ng-repeat="(key, firstLevelMenu) in ::menu.children()" data-menu-id="{{ ::firstLevelMenu.uuid }}" compile="firstLevelMenu.template()">
                <a ng-if="::firstLevelMenu.hasChild()" ng-click="toggleMenu(firstLevelMenu)" ng-class="::{'active': firstLevelMenu.isActive(path)}">
                    <span compile="::firstLevelMenu.icon()"><span class="glyphicon glyphicon-list"></span></span>

                    {{ firstLevelMenu.title() | translate }}
                    <span class="glyphicon arrow" ng-class="::{'glyphicon-menu-down': isOpen(firstLevelMenu), 'glyphicon-menu-right': !isOpen(firstLevelMenu) }"></span>

                </a>
                <a ng-if="::!firstLevelMenu.hasChild()" href="#{{ firstLevelMenu.link() }}" ng-click="activateLink(firstLevelMenu)" ng-class="::{'active': firstLevelMenu.isActive(path)}">
                    <span compile="::firstLevelMenu.icon()"><span class="glyphicon glyphicon-list"></span></span>
                    
                    {{ firstLevelMenu.title() | translate }}

                </a>
                <ul ng-if="::firstLevelMenu.hasChild()" class="nav nav-second-level collapsible" data-menu-id="{{ ::firstLevelMenu.uuid }}" ng-class="::{'collapsed': !isOpen(firstLevelMenu) }">
                    <li ng-repeat="secondLevelMenu in ::firstLevelMenu.children()" data-menu-id="{{ ::secondLevelMenu.uuid }}" compile="secondLevelMenu.template()">
                        <a href="#{{secondLevelMenu.link()}}" ng-click="activateLink(secondLevelMenu, firstLevelMenu)" ng-class="::{'active': secondLevelMenu.isActive(path)}">
                            <span compile="::secondLevelMenu.icon()"><span class="glyphicon glyphicon-list"></span></span>
                            {{ secondLevelMenu.title() | translate }}
                        </a>
                    </li>
                </ul>
            </li>
        </ul>
    </div>
</div>

If you use any comparator , you will observe the only difference between menubar.html ( https://github.com/marmelab/ng-admin/blob/master/src/javascripts/ng-admin/Main/view/menuBar.html) and the customizedMenubar.html is

ng-click="activateLink(secondLevelMenu, firstLevelMenu)

And some renaming of iterator variables in ng-repeat from menu to firstLevelMenu and SecondLevelMenu.

Note: The above solution will not highlight the relevant menu item when a user changes the address bar to point to some other menu item. To fix that change locationChangeSuccess listener to make it capable to get activeMenu item either based on address bar of browser or from scope.activateLink(this was already done above )

` var listener = $rootScope.$on('$locationChangeSuccess', function() {

      scope.path = $location.path();
      if (!activeMenu) {
        const menuObj = Utils.getActiveAndParentMenuByLocation(scope.menu.children(), scope.path);
        activeMenu = menuObj.activeMenu;
        activeParentMenu = menuObj.activeParentMenu;
      }
      updateLeftMenuStyling(activeMenu , activeParentMenu);
      activeMenu = null;
      activeParentMenu = null;
    });

`
where Utils.getActiveAndParentMenuByLocation() method will use Array.find() to get activeMenu and activeParentMenu object by comparing location.path === menu['_link']

Thanks for coming this far and reading it :)

@edgarmarkosov
Copy link

Any fix for this issue?

@ashwanikumar415
Copy link
Author

Easiest workaround for this issue not to reproduce is setting autoClose(false) like below

var master = nga.menu(); master.autoClose(false);

Assuming master holds all the other submenu objects

@edgarmarkosov
Copy link

But what if I want to use auto close option. I used your previous solution in ng-admin source, it worked. but I wanted to know if there was plan to solve this issue in the original ng-admin repository.

@vuquangtam
Copy link

Above solutions don't work for me. Found out my solution for this, add this css

.collapsed  {
    height: 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants