【问题标题】:dynamic menu items using AngularJS使用 AngularJS 的动态菜单项
【发布时间】:2013-01-12 19:30:47
【问题描述】:

假设我有以下菜单结构:

    <li class="dropdown"><img role="button" class="dropdown-toggle" data-toggle="dropdown" ng-src="{{avatarUrl}}" />
      <ul class="dropdown-menu pull-right" role="menu">
        <li ng-hide="user"><a ng-click="openLoginDialog()">Login</a></li>
        <li ng-show="user"><a ng-click="logout()">Logout</a></li>
      </ul>
    </li>

我得到了正确的菜单,但是因为我使用的是 ng-show/ng-hide,所以当我在控制器中以编程方式更改 user = false; 时,会出现登录菜单。我明白为什么会发生这种情况,但我不确定在使用 Angular 时要采取什么方法来防止它。我尝试了一个 ng-repeat:

    <li class="dropdown"><img role="button" class="dropdown-toggle" data-toggle="dropdown" ng-src="{{avatarUrl}}" />
      <ul class="dropdown-menu pull-right" role="menu">
        <li ng-repeat="action in actions"><a ng-click="{{action.command}}">{{action.name}}</li>
      </ul>
    </li>

与:

$scope.actions = [ {
  name : "Login",
  command : "openLoginDialog()"
}, {
  name : "Logout",
  command : "logout()"
} ];

但是使用该策略,我单击菜单项不会发生任何事情。我不确定对于我确定是行人用例的适当 Angular 方法。

【问题讨论】:

    标签: javascript twitter-bootstrap angularjs


    【解决方案1】:

    使用 ng-switch 代替 ng-show/hide。 ng-switch 从 DOM 中添加/删除元素。

    <ul class="dropdown-menu pull-right" role="menu">
        <li ng-switch="user">
           <a ng-switch-when="true" ng-click="logout()">Logout</a>
           <a ng-switch-default     ng-click="openLoginDialog()">Login</a>
        </li>
    </ul>
    

    更新以处理@andyczerwonka 的评论。将 ng-switch 向上移动一到两级。如果spans 在ul 里面,别打扰你:

    <ul class="dropdown-menu pull-right" role="menu" ng-switch="user">
      <span ng-switch-when="true">
        <li><a  ng-click="logout()">Logout</a></li>
        <li><a  ng-click="preferences()">Preferences</a></li>
      </span>
      <span ng-switch-default>
        <li><a ng-click="openLoginDialog()">Login</a></li>
      </span>
    </ul>
    

    要不然,在ul之外加一个span怎么样:

    <span ng-switch="user">
      <ul class="dropdown-menu pull-right" role="menu" ng-switch-when="true">
          <li><a  ng-click="logout()">Logout</a></li>
          <li><a  ng-click="preferences()">Preferences</a></li>
        </ul>
      <ul class="dropdown-menu pull-right" role="menu" ng-switch-default>
          <li><a ng-click="openLoginDialog()">Login</a></li>
      </ul>
    </span>
    

    Fiddle 显示这两种方法。

    【讨论】:

    • 这对我不起作用,因为如果我有两个以上的菜单项,ng-switch 将不起作用。假设我想在用户未登录时显示一个菜单项,例如登录,当他登录时有两个,例如首选项和注销。我认为ng-switch 不会处理这种情况。
    • 使用此方法的行为与ng-show\ng-hide 策略相同。注销时,会出现登录菜单。
    • 试着放一个小提琴或 plunkr。
    • 这是我尝试使用ng-repeatan example,但操作不执行。 Here's a video 使用您上面提到的策略注销时出现的菜单。我将尝试将其提取到一个示例中。
    • 我认为这更像是一个引导程序问题。 plnkr.co/edit/wkUClK9OBLK8EWI5D8Fn?p=preview
    【解决方案2】:

    在我的项目中,我使用以下设置:

    angular.module('mymodule')
    .controller('MenuCtrl', function ($scope, $translate, UserService) {
    

    使用允许使用这些操作的角色定义操作:

      $scope.actions = [ {
        name : "menu.login",
        href : "#/login",
        roles : []
      }, {
        name : "menu.logout",
        href : "#/logout",
        roles : [ 'READ_ONLY', 'ADMIN' ]
      }, {
        name : "menu.foo",
        href : "#/foo",
        roles : [ 'READ_ONLY', 'ADMIN' ]
      }, {
        name : "menu.adminArea",
        href : "#/adminArea",
        roles : [ 'ADMIN' ]
      } ];
    

    定义一个 isAllowed 函数来确定当前用户是否可以使用某个操作:

      $scope.isAllowed = function(action) {
        if (action.roles && action.roles.length) {
          for ( var i = 0; i < action.roles.length; ++i) {
            if (jQuery.inArray(action.roles[i], UserService.roles) >= 0) {
              return true;
            }
          }
          return false;
        } else {
          return !(UserService.roles && UserService.roles.length);
        }
      };
    

    然后使用 $roueChangeSuccess 事件来确定应该为当前用户显示哪些操作:

      $scope.initView = function() {
        for(var i=0; i<$scope.actions.length; ++i) {
          var action = $scope.actions[i];
          if($scope.isAllowed(action)) {
            action.isRendered = true;
          } else {
            action.isRendered = false;
          }
        }
      };
    
      $scope.$on('$routeChangeSuccess', function() {
        $scope.initView();
      });
    
    });
    

    最后,这是我的菜单模板:

    <nav ng-controller="MenuCtrl">
      <ul>
        <span ng-repeat="action in actions" ng-switch on="action.isRendered">
          <li ng-switch-when="true"><a href="{{action.href}}">{{action.name | translate}
          </a></li>
        </span>
      </ul>
    </nav>
    

    【讨论】:

      【解决方案3】:

      你为什么不给你的命令分配函数:

      var openLoginDialog = function() { ... };
      var logout = function() { ... };
      
      $scope.actions = [ {
        name : "Login",
        command : openLoginDialog
      }, {
        name : "Logout",
        command : logout
      } ];
      

      【讨论】:

      • 我做了,但是当我以这种方式添加它们时,这些项目不会执行。他们显示得很好,但他们不会执行。我不知道为什么。
      • 我认为这是您使用的 angularjs 版本的问题。这是plunker,我在其中使用了角度版本 1.1.5 并且工作正常。 :)
      猜你喜欢
      • 2014-12-25
      • 2016-07-21
      • 2013-10-20
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 2014-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多