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

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

Поскольку в моем навигационном меню может быть бесконечное количество подменю, мне пришлось использовать рекурсивную директиву для построения родительской/дочерней навигационной структуры. Теперь я пытаюсь понять, как превратить его в функциональную структуру dropmenu. Я просматривал angularui-bootstrap, и у них есть Dropdown Toggle, который имеет некоторые базовые функции dropmenu, но, поскольку я использовал рекурсивную директиву, в моей структуре меню уже были прикреплены классы css, сгенерированные angularjs. В выпадающем меню 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. Важной частью является рекурсивная директива. Ниже вы найдете ссылку на проект plunker. Кто-нибудь может мне помочь?

Проект Plunker ---------------- ------------------------------------------------------------

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

Навигационные элементы по-прежнему отображаются в 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;
}

Он был получен из официального файла bootstrap 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». Верна ли эта моя догадка?


person David Pugh    schedule 24.11.2013    source источник
comment
не понимая, почему классы имеют значение. Элемент может иметь множество классов. Также вы можете изменить или даже не использовать CSS из раскрывающегося списка пользовательского интерфейса.   -  person charlietfl    schedule 25.11.2013
comment
У меня была аналогичная проблема, и я решил ее, используя это: stackoverflow.com/questions/11854514/. Это поможет вам создать структуру angular-bootstrap. У меня была проблема с дублированием элементов при обновлении из службы, но это для нового вопроса.   -  person Martin Nuc    schedule 25.11.2013
comment
Charlietfl, привет, я не думал о нескольких классах CSS для каждого элемента. Я добавил соответствующие классы в соответствии с документацией angular-ui.github.io/bootstrap/#/ get_started и теперь все это невидимо. Структура элементов есть в DOM (firebug), но вы не можете видеть ни одну из категорий в структуре навигации. Я добавил «ui.bootstrap» в качестве зависимости к модулю моего контроллера и добавил ui-bootstrap-tpls-0.7.0.min.js на свою страницу index.html, я также добавил bootstrap.css и даже добавил этот дополнительный css линия согласно документации. Есть идеи?   -  person David Pugh    schedule 25.11.2013
comment
Charlietfl, я создал отдельный проект Plunker, в котором как раз есть изменения для добавления классов css в нужный html. plnkr.co/edit/f0H3Yg?p=preview   -  person David Pugh    schedule 25.11.2013


Ответы (1)


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

Текущая демонстрация здесь (нажмите).

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

js:

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;
}
person m59    schedule 24.11.2013
comment
Хорошо, я проверил вашу демонстрацию. Родительское меню закрывается, когда вы нажимаете, чтобы открыть дочернее меню. Похоже, библиотека должна обрабатывать это для подменю.... - person David Pugh; 25.11.2013
comment
@thebravedave да, к сожалению, я почти полностью уверен, что это не предназначено. Одна вещь, которую следует учитывать, это то, что такие вложенные подменю являются плохой практикой. После одного уровня это своего рода стресс для пользователя (сколько еще таких мне нужно пройти!?). Однако вы можете легко создать свою собственную функциональность здесь. - person m59; 25.11.2013
comment
ну, оптимально, у вас также будет какая-то функция наведения. - person David Pugh; 25.11.2013