指令中的子菜单不起作用

时间:2021-10-29 07:19:21

I have a multi-tiered menu that works fine as hard-coded html. As soon as I move the sub-menu pieces into an angularJs directive (nav-dropdown) it no longer works correctly, and instead closes the parent menu when I click on the sub-menu item. The resulting HTML is the same other than some AngularJS classes and attributes that should be ignored by everything other than AngularJS.

我有一个多层菜单,可以像硬编码的html一样工作。一旦我将子菜单片段移动到angularJs指令(nav-dropdown),它就不再正常工作,而是在我点击子菜单项时关闭父菜单。生成的HTML与一些AngularJS类和属性不同,除了AngularJS之外,其他所有内容都应该忽略它们。

See the plunkr here: http://plnkr.co/edit/YknatvTulTC0FM2fXkSc?p=preview

请参阅此处的plunkr:http://plnkr.co/edit/YknatvTulTC0FM2fXkSc?p = preview

Notice how sub-menus under "Dropdown" behave correctly (open sub-menus on click). All the other sub-menus which are generated dynamically do not work.

请注意“下拉列表”下的子菜单如何正常运行(单击时打开子菜单)。动态生成的所有其他子菜单都不起作用。

Dropdown html (works):

下拉html(有效):

<li class="dropdown open">
    <a tabindex="0" data-toggle="dropdown" data-submenu="" aria-expanded="true">
      Dropdown<span class="caret"></span>
    </a>

    <ul class="dropdown-menu">
      <li class="dropdown-submenu">
        <a tabindex="0">Action</a>

        <ul class="dropdown-menu">
          <li><a tabindex="0">Sub action</a></li>
          <li class="dropdown-submenu">
            <a tabindex="0">Another sub action</a>

            <ul class="dropdown-menu">
              <li><a tabindex="0">Sub action</a></li>
              <li><a tabindex="0">Another sub action</a></li>
              <li><a tabindex="0">Something else here</a></li>
            </ul>
          </li>
          <li><a tabindex="0">Something else here</a></li>
          <li class="dropdown-submenu">
            <a tabindex="0">Another action</a>

            <ul class="dropdown-menu">
              <li><a tabindex="0">Sub action</a></li>
              <li><a tabindex="0">Another sub action</a></li>
              <li><a tabindex="0">Something else here</a></li>
            </ul>
          </li>
        </ul>
      </li>

      <li class="dropdown-submenu">
        <a tabindex="0">Another action</a>

        <ul class="dropdown-menu">
          <li><a tabindex="0">Sub action</a></li>
          <li><a tabindex="0">Another sub action</a></li>
          <li><a tabindex="0">Something else here</a></li>
        </ul>
      </li>
      <li><a tabindex="0">Something else here</a></li>
      <li class="divider"></li>
      <li><a tabindex="0">Separated link</a></li>
    </ul>
</li>

Dynamic html from angularjs directive (does not work):

来自angularjs指令的动态html(不起作用):

<li class="dropdown ng-scope ng-isolate-scope open" ng-repeat="department in vm.departments" department="department">
    <a tabindex="0" data-toggle="dropdown" data-submenu="" class="ng-binding ng-scope" aria-expanded="true">
      Apparel<span class="caret"></span>
    </a>

    <ul class="dropdown-menu ng-scope">
      <li class="dropdown-submenu">
        <a tabindex="0">Action</a>

        <ul class="dropdown-menu">
          <li><a tabindex="0">Sub action</a></li>
          <li class="dropdown-submenu">
            <a tabindex="0">Another sub action</a>

            <ul class="dropdown-menu">
              <li><a tabindex="0">Sub action</a></li>
              <li><a tabindex="0">Another sub action</a></li>
              <li><a tabindex="0">Something else here</a></li>
            </ul>
          </li>
          <li><a tabindex="0">Something else here</a></li>
          <li class="dropdown-submenu">
            <a tabindex="0">Another action</a>

            <ul class="dropdown-menu">
              <li><a tabindex="0">Sub action</a></li>
              <li><a tabindex="0">Another sub action</a></li>
              <li><a tabindex="0">Something else here</a></li>
            </ul>
          </li>
        </ul>
      </li>

      <li class="dropdown-submenu">
        <a tabindex="0">Another action</a>

        <ul class="dropdown-menu">
          <li><a tabindex="0">Sub action</a></li>
          <li><a tabindex="0">Another sub action</a></li>
          <li><a tabindex="0">Something else here</a></li>
        </ul>
      </li>
      <li><a tabindex="0">Something else here</a></li>
      <li class="divider"></li>
      <li><a tabindex="0">Separated link</a></li>
    </ul>
  </li>

Here's the full javascript, which you can see on plunkr:

这是完整的javascript,你可以在plunkr上看到:

// Code goes here

angular.module('myApp', []);

angular.module('myApp').directive('dccNavigation', function (departmentService) {
    return {
        restrict: 'E',
        scope: {
            brandName: '@',
            brandImage: '@'
        },
        replace: true,
        templateUrl: 'navigation.html',
        controllerAs: 'vm',
        controller: function($scope, $timeout) {
          var vm = this;
          vm.departments = [];
          vm.brandName = $scope.brandName;
          vm.brandImage = $scope.brandImage;
          $('[data-submenu]').submenupicker();

          departmentService.getDepartments().then(function(success) {
            vm.departments = success.data.departments;
          });
        }
    }
});

angular.module('myApp').directive('dccNavDropdown', function ($compile) {
    return {
        restrict: 'E',
        scope: {
            department: '=department',
        },
        replace: true,
        templateUrl: 'nav-dropdown.html',
        controller: 'navDropdownController',
        controllerAs: 'vm',
        compile: function (el) {
            var contents = el.contents().remove();
            var compiled;
            return function(scope,el){
                if(!compiled)
                    compiled = $compile(contents);

                compiled(scope,function(clone){
                    el.append(clone);
                });
            };
        }
    }
});

angular.module('myApp').controller('navDropdownController', function($scope, departmentService){
      var vm = this;
      vm.department = $scope.department;
});

angular.module('myApp').factory('departmentService', function($q){
  var customNavElements = [];

  return {
      customNavElements: customNavElements,
      getDepartments: function() {
        var departments =[
          {"id":18245,"name":"Apparel","level":1,"itemCount":5,"children":[
            {"id":3509,"name":"Men","level":2,"itemCount":5,"children":[
              {"id":18112,"name":"Jackets","level":3,"itemCount":0,"children":[]},
                 {"id":18113,"name":"Polos","level":3,"itemCount":0,"children":[]},
                 {"id":18114,"name":"Sweatshirts","level":3,"itemCount":0,"children":[]},
                 {"id":18115,"name":"T-Shirts","level":3,"itemCount":0,"children":[]},
                 {"id":18499,"name":"View all","level":3,"itemCount":0,"children":[]}]},
              {"id":3510,"name":"Women","level":2,"itemCount":4,"children":
                [{"id":18116,"name":"Jackets","level":3,"itemCount":0,"children":[]},
                 {"id":18118,"name":"Sweatshirts","level":3,"itemCount":0,"children":[]},
                 {"id":18119,"name":"T-Shirts","level":3,"itemCount":0,"children":[]},
                 {"id":18500,"name":"View all","level":3,"itemCount":0,"children":[]}]},
              {"id":3513,"name":"Hats","level":2,"itemCount":0,"children":[]},
              {"id":5023,"name":"Kids","level":2,"itemCount":0,"children":[]},
              {"id":18468,"name":"View All","level":2,"itemCount":0,"children":[]}]},
            {"id":3514,"name":"Accessories","level":1,"itemCount":7,"children":[
              {"id":18120,"name":"Drinkware","level":2,"itemCount":0,"children":[]},
              {"id":18121,"name":"Bags","level":2,"itemCount":0,"children":[]},
              {"id":18122,"name":"Office","level":2,"itemCount":0,"children":[]},
              {"id":18124,"name":"High-end Tech Items","level":2,"itemCount":0,"children":[]},
              {"id":18123,"name":"Tradeshow/Giveaways","level":2,"itemCount":0,"children":[]},
              {"id":18226,"name":"Misc","level":2,"itemCount":0,"children":[]},
              {"id":18411,"name":"View All","level":2,"itemCount":0,"children":[]}]},
            {"id":14961,"name":"Monday Night Football","level":1,"itemCount":0,"children":[]},
            {"id":3515,"name":"Golf","level":1,"itemCount":3,"children":[
              {"id":18125,"name":"Apparel","level":2,"itemCount":0,"children":[]},
              {"id":18126,"name":"Accessories","level":2,"itemCount":0,"children":[]},
              {"id":18127,"name":"View All","level":2,"itemCount":0,"children":[]}]},
            {"id":18080,"name":"Shop by Price","level":1,"itemCount":4,"children":[
              {"id":18081,"name":"Under $5.00","level":2,"itemCount":0,"children":[]},
              {"id":18082,"name":"$5.00 - $10.00","level":2,"itemCount":0,"children":[]},
              {"id":18083,"name":"$10.01 - $25.00","level":2,"itemCount":0,"children":[]},
              {"id":18084,"name":"Over $25.00","level":2,"itemCount":0,"children":[]}]},
            {"id":3516,"name":"Sales","level":1,"itemCount":8,"children":[
              {"id":16927,"name":"Men","level":2,"itemCount":4,"children":[
                {"id":18128,"name":"Jacket","level":3,"itemCount":0,"children":[]},
                {"id":18129,"name":"Polos","level":3,"itemCount":0,"children":[]},
                {"id":18130,"name":"Sweatshirts","level":3,"itemCount":0,"children":[]},
                {"id":18131,"name":"T-Shirts","level":3,"itemCount":0,"children":[]}]},
              {"id":16928,"name":"Women","level":2,"itemCount":3,"children":[
                {"id":18132,"name":"Jackets","level":3,"itemCount":0,"children":[]},
                {"id":18134,"name":"Sweatshirts","level":3,"itemCount":0,"children":[]},
                {"id":18135,"name":"T-Shirts","level":3,"itemCount":0,"children":[]}]},
              {"id":16929,"name":"Kids","level":2,"itemCount":0,"children":[]},
                {"id":16930,"name":"Hats","level":2,"itemCount":0,"children":[]},
                {"id":16931,"name":"Accessories","level":2,"itemCount":5,"children":[
                  {"id":18136,"name":"Drinkware","level":3,"itemCount":0,"children":[]},
                  {"id":18137,"name":"Bags","level":3,"itemCount":0,"children":[]},
                  {"id":18138,"name":"Office","level":3,"itemCount":0,"children":[]},
                  {"id":18139,"name":"Tradeshow/Givaways","level":3,"itemCount":0,"children":[]},
                  {"id":18304,"name":"Misc","level":3,"itemCount":0,"children":[]}]},
                {"id":16932,"name":"Golf","level":2,"itemCount":3,"children":[
                  {"id":18141,"name":"Apparel","level":3,"itemCount":0,"children":[]},
                  {"id":18142,"name":"Accessories","level":3,"itemCount":0,"children":[]},
                  {"id":18143,"name":"View All","level":3,"itemCount":0,"children":[]}]},
                {"id":16933,"name":"Monday Night Football","level":2,"itemCount":0,"children":[]},
                {"id":16934,"name":"View All","level":2,"itemCount":0,"children":[]}]}];
        var deferred = $q.defer();
        setTimeout(function(){
            deferred.resolve({ data: { departments: departments }});
        }, 100);
        return deferred.promise;
      }
  }
});

I'm using the bootstrap-submenu project: http://vsn4ik.github.io/bootstrap-submenu/

我正在使用bootstrap-submenu项目:http://vsn4ik.github.io/bootstrap-submenu/

1 个解决方案

#1


0  

The line of code that applies the behavior to the submenu's is:

将行为应用于子菜单的代码行是:

$('[data-submenu]').submenupicker();

The problem is that this line of code is executed before the sub-menu's exist, so the behavior is never applied. The fix is to wrap this code in a $timeout function AFTER the sub-menu items (departments) are added to the scope. Wrapping it allows the AngularJS $digest cycle to complete and all elements to be attached to the DOM before adding sub-menu behavior.

问题是这行代码是在子菜单存在之前执行的,因此从不应用该行为。修复是在将子菜单项(部门)添加到范围后将此代码包装在$ timeout函数中。包装它允许完成AngularJS $摘要周期,并在添加子菜单行为之前将所有元素附加到DOM。

Working Plunkr: http://plnkr.co/edit/c8g43JxntmOXgZI0Wo05?p=preview

工作Plunkr:http://plnkr.co/edit/c8g43JxntmOXgZI0Wo05?p=preview

departmentService.getDepartments().then(function(success) {
    vm.departments = success.data.departments;
    $timeout(function(){
      $('[data-submenu]').submenupicker();
    }, 500);
  });

#1


0  

The line of code that applies the behavior to the submenu's is:

将行为应用于子菜单的代码行是:

$('[data-submenu]').submenupicker();

The problem is that this line of code is executed before the sub-menu's exist, so the behavior is never applied. The fix is to wrap this code in a $timeout function AFTER the sub-menu items (departments) are added to the scope. Wrapping it allows the AngularJS $digest cycle to complete and all elements to be attached to the DOM before adding sub-menu behavior.

问题是这行代码是在子菜单存在之前执行的,因此从不应用该行为。修复是在将子菜单项(部门)添加到范围后将此代码包装在$ timeout函数中。包装它允许完成AngularJS $摘要周期,并在添加子菜单行为之前将所有元素附加到DOM。

Working Plunkr: http://plnkr.co/edit/c8g43JxntmOXgZI0Wo05?p=preview

工作Plunkr:http://plnkr.co/edit/c8g43JxntmOXgZI0Wo05?p=preview

departmentService.getDepartments().then(function(success) {
    vm.departments = success.data.departments;
    $timeout(function(){
      $('[data-submenu]').submenupicker();
    }, 500);
  });