Многоуровневое раскрывающееся меню AngularJS для структуры меню, созданной из рекурсивной директивы

У меня есть слабый рассол здесь. Я должен получить свое многоуровневое навигационное меню от вызова веб-службы.

Поскольку в моем меню навигации может быть бесконечное количество подменю, мне пришлось использовать рекурсивную директиву для построения структуры навигации родитель / потомок. Сейчас я пытаюсь понять, как превратить его в функциональную структуру дропменю. Я взглянул на angularui-bootstrap, и у них есть Dropdown Toggle, который имеет некоторые базовые функциональные возможности dropmenu, но так как я использовал рекурсивную директиву, моя структура меню уже имеет сгенерированные angularjs классы css. В выпадающих меню angularjs-bootstrap есть классы css, которые отличаются от классов, сгенерированных моим angularjs... вот!

<ul>
    <li ng-repeat="parent in parents" class="ng-scope">
        <recursive-list-item on-node-click="onNodeClickFn(node)" parent="parent" class="ng-isolate-scope ng-scope">
            <a data-ng-click="onNodeClick({node: parent})" href="javascript:void(0)" class="ng-scope ng-binding">Clothes</a>
            <!-- ngIf: parent.children.length > 0 -->
            <ul data-ng-if="parent.children.length &gt; 0" class="ng-scope">
                <!-- ngRepeat: child in parent.children -->
                <li ng-repeat="child in parent.children" class="ng-scope">
                    <recursive-list-item data-on-node-click="onNodeClickFn(node)" data-parent="child" class="ng-isolate-scope ng-scope">
                        <a data-ng-click="onNodeClick({node: parent})" href="javascript:void(0)" class="ng-scope ng-binding">Gortex Jackets</a>
                        <!-- ngIf: parent.children.length > 0 -->
                    </recursive-list-item>
                </li>
                <!-- end ngRepeat: child in parent.children -->
                ...
                ...
                ...
            </ul>
        </recursive-list-item>
    </li>
    <!-- end ngRepeat: child in parent.children -->
...
...
</ul>

Это был пример HTML, который генерируется как окончательный вывод для моего рекурсивного меню навигации. Если он настроен таким образом, все подменю ng-click активны и имеют ту же область видимости, что и основной контроллер (все денди, за исключением того, что оно не похоже на выпадающее меню)

Вот пример структуры dropmenu для angularjs-bootstrap

<li class="dropdown" ng-controller="DropdownCtrl">
  <a class="dropdown-toggle">
    Click me for a dropdown, yo!
  </a>
  <ul class="dropdown-menu">
    <li ng-repeat="choice in items">
      <a>{{choice}}</a>
    </li>
  </ul>
</li>

У него очень отличная структура класса CSS, чем у меня, так что "выпадающий" angularjs-bootstrap не будет работать с моим.

У кого-нибудь есть предложения для меня? Имейте в виду, что, поскольку я получаю свою структуру навигации через json через вызов веб-службы, я должен использовать рекурсивные angularjs для создания структуры родительского / дочернего меню.

Если кто-то запутается в моей html директиве, сгенерированной здесь, я могу показать свой собственный код директивы, но пока не попросит краткости. Мой пользовательский код директивы работает только для построения структуры навигации и сохраняет все области директив, связанные с областью действия основного контроллера (т. Е. Активным нажатием), но он не имеет стиля / прокрутки активен.

Моя не функциональная навигация по меню

***** ОБНОВЛЕНИЕ ******** Я создал репликацию плунжера, которая почти такая же. В моем проекте я получал данные своего меню навигации из службы angularjs, которая выполняла бы вызов веб-службы для остальных веб-служб на моем сервере, но у меня этого нет, поэтому я просто вручную создал json для каждого из моих сервисы, которые делают вызовы REST webservice. Важной частью является рекурсивная директива. Справа внизу вы найдете ссылку на проект plunker. Кто-нибудь может мне помочь?

Проект Плункер ------------------------------------------------ -------------

************* НОВОЕ ОБНОВЛЕНИЕ ***************** Комментарий от Charlietfl о том, что я могу иметь несколько классов css в моей структуре выпадающего меню навигации. Я пытаюсь сделать это с помощью angularui-bootstrap. Я следовал инструкциям по добавлению этого в свой проект и создал новый проект Plunker, основанный на старом проекте plunker, но с дополнительными классами dropmenu css, добавленными в структуру навигации. Вот проект Плункер: Проект Плункер

Элементы навигации по-прежнему отображаются в DOM, но они не видны. Я посмотрел на CSS для первого элемента ul, и это так:

*, *:before, *:after {
    -moz-box-sizing: border-box;
}
*, *:before, *:after {
    -moz-box-sizing: border-box;
}
.dropdown-menu {
    background-clip: padding-box;
    background-color: #FFFFFF;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 4px;
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176);
    display: none;
    float: left;
    font-size: 14px;
    left: 0;
    list-style: none outside none;
    margin: 2px 0 0;
    min-width: 160px;
    padding: 5px 0;
    position: absolute;
    top: 100%;
    z-index: 1000;
}

Он был получен из официального файла начальной загрузки css. Не уверен точно, почему это не видно. Не уверен, что это поможет, но вот CSS для следующего элемента li после ul

*, *:before, *:after {
    -moz-box-sizing: border-box;
}
*, *:before, *:after {
    -moz-box-sizing: border-box;
}
.dropdown {
    position: relative;
}
.dropup, .dropdown {
    position: relative;
}
li {
    line-height: 20px;
}
*, *:before, *:after {
    -moz-box-sizing: border-box;
}

Имейте в виду, что вам нужно перейти на страницу plunker, чтобы увидеть обновленный код, начиная с того момента, когда я добавил теги css, необходимые для angularui-bootstrap. Чтобы увидеть невидимые элементы навигации, вам понадобится что-то вроде Firebug, чтобы увидеть DOM.

Вот пример некоторого окончательного вывода html (из DOM) из моего обновления, чтобы попытаться поработать с классами angularui-bootstrap css.

...
<li ng-repeat="child in parent.children" class="dropdown ng-scope">
            <recursive-list-item data-on-node-click="onNodeClickFn(node)" data-parent="child" class="ng-isolate-scope ng-scope">
            <a class="dropdown-toggle ng-scope ng-binding" href="javascript:void(0)">Kids Clothes</a>
...

Я подозреваю, что причина, по которой библиотека angularui-bootstrap не работает, заключается в том, что элемент "recursive-list-item.." является дочерним элементом элемента "li" и родительским элементом для элемента "a". Правильно ли это мое предположение?

1 ответ

Это то, что я использую, и у него много дополнительных функций, которые довольно приятны. Смотрите использование $scope.menu и что происходит, когда вы раскрываете раскрывающийся список - вы можете добавлять заголовки, разделители и даже прикреплять функции щелчка. Обратите внимание, что вы можете вложить как можно больше ul как вы хотите, и хотя переключение работает, оно бесполезно, так как нажатие, чтобы открыть подменю, скроет его родителя. Насколько я знаю, вам нужно было бы создать свой собственный обработчик javascript или пользовательский css, используя hovers, если вы хотите более глубокое вложение в меню.

Живая демо здесь (нажмите).

<nav>
  <div menu="menu"></div> <!-- the element here doesn't matter -->
</nav>

ЯШ:

var app = angular.module('myApp', ['ui.bootstrap']);

app.directive('menu', function() {
  return {
    restrict: 'A',
    scope: {
      menu: '=menu',
      cls: '=ngClass'
    },
    replace: true,
    template: '<ul><li ng-repeat="item in menu" menu-item="item"></li></ul>',
    link: function(scope, element, attrs) {
      element.addClass(attrs.class);
      element.addClass(scope.cls);
    }
  };
});

app.directive('menuItem', function($compile) {
  return {
    restrict: 'A',
    replace: true,
    scope: {
      item: '=menuItem'
    },
    template: '<li active-link><a href={{item.href}}>{{item.title}}</a></li>',
    link: function (scope, element, attrs) {
      if (scope.item.header) {
        element.addClass('nav-header');
        element.text(scope.item.header);
      }
      if (scope.item.divider) {
        element.addClass('divider');
        element.empty();
      }
      if (scope.item.submenu) {
        element.addClass('dropdown');

        var text = element.children('a').text();
        element.empty();
        var $a = $('<a class="dropdown-toggle">'+text+'</a>');
        element.append($a);

        var $submenu = $('<div menu="item.submenu" class="dropdown-menu"></div>');
        element.append($submenu);
      }
      if (scope.item.click) {
        element.find('a').attr('ng-click', 'item.click()');
      }
      $compile(element.contents())(scope);
    }
  };
});

app.controller('myCtrl', function($scope) {
  $scope.menu = [
    {
      "title": "Home",
      "href": "#"
    },
    {
      "title": "About",
      "href": "about"
    },
    {
      "title": "History",
      "href": "about/history"
    },
    {
      "title": "Contact",
      "href": "contact"
    },
    {
      "title": "Other things - in a list. (Click here)",
      "submenu": [
        {
          "header": "Sample Header"
        },
        {
          "title": "Some Link",
          "href": "some/place"
        },
        {
          "title": "Another Link",
          "href": "some/other/place"
        },
        {
          "divider": "true"
        },
        {
          "header": "Header 2"
        },
        {
          "title": "Again...a link.",
          "href": "errrr"
        },
        {
          "title": "Nest Parent",
          "submenu": [
            {
              "title": "nested again",
              "href": "nested/again"
            },
            {
              "title": "me too",
              "href": "sample/place"
            }
          ]
        }
      ]
    }
  ];
});

Обновление для вложенного выпадающего списка:

Живая демо здесь (нажмите).

.dropdown-menu .dropdown-menu {
  margin: 0;
  left: 100%;
  top: -5px;
}

.dropdown-menu li:hover .dropdown-menu {
  display: block;
}
Другие вопросы по тегам