AngularJS directive toggle menu preventing default for other directive

纵饮孤独 提交于 2019-12-04 16:50:37

Basic idea is that you need to share the state between all your dropdown submenus, so when one of them is shown, all others are hidden. The simpliest way of storing state (such as opened or closed) are... CSS classes!

We'll create a pair of directives - one for menu, and another for sumbenu. It is more expressive that just divs.

Here is out markup.

<menu>
  <submenu data-caption="Button 1">
    Content 1
  </submenu>
  <submenu data-caption="Button 2">
    Content 2
  </submenu>
</menu>

Look how readable is it! Say thanks to directives:

plunker.directive("menu", function(){
    return {
        restrict : "E",
        scope : {},
        transclude : true,
        replace : true,
        template : "<div class='menu' data-ng-transclude></div>",
        controller : function ($scope, $element, $attrs, $transclude){
            $scope.submenus = [];

            this.addSubmenu = function (submenu) {
                $scope.submenus.push(submenu);
            }

            this.closeAllSubmenus = function (doNotTouch){
                angular.forEach($scope.submenus, function(submenu){
                    if(submenu != doNotTouch){
                        submenu.close();    
                    }
                })
            }
        }
    }
});

plunker.directive("submenu", function(){
    return {
        restrict : "E",
        require : "^menu",
        scope : {
            caption : "@"
        },
        transclude : true,
        replace : true,
        template : "<div class='submenu'><label>{{caption}}</label><div class='submenu-content' data-ng-transclude></div></div>",
        link : function ($scope, $iElement, $iAttrs, menuController) {
            menuController.addSubmenu($scope);

            $iElement.bind("click", function(event){
                menuController.closeAllSubmenus($scope);
                $iElement.toggleClass("active");
            });

            $scope.close = function (){
                $iElement.removeClass("active");
            }
        }
    }
});

Look thar we restricted them to HTML elements (restrict : "E"). submenu requires to be nested in menu (require : "^menu"), this allows us to inject menu controller to submenu's link function. transclude and replace controls the position of original markup in compiled HTML output (replace=true means that original markup will be replaced with compiled, transclude inserts parts of original markup to compiled output).

When we've done with this, we just say to menu close all your child menus! and menu iterates over submenus, forcing them to close.

We are adding childs to menu controller in addSubmenu function. It is called in submenus link function, thus every compiled instance of submenu adds itself to menu. Now, closing all submenus is as easy as iterating over all children, this is done by closeAllSubmenus in menu controller.

Here is a full Plunker to play with.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!