Я хочу представить категорию корзины покупок в виде древовидной структуры. Когда я нажимаю на родительский элемент ul>li, он получает данные с сервера и динамически добавляет новый набор данных. У меня есть n уровней, изначально, когда я нажимаю на первый уровень, я создаю динамический набор дочерних элементов и помещаю его под родительским, используя его имя класса. Та же функция вызывается для вновь созданного дочернего элемента, но на этот раз она обновляет родительский элемент, по которому щелкнул элемент. Я создал плункер для подробного объяснения.

Когда я нажимаю на категорию мужчин, ее дочерние элементы заполняются:

  • наручные часы для мужчин
  • Рубашка

Когда я нажимаю «наручные часы для мужчин», он должен добавить следующий уровень ниже, но это перезапись существующих данных.

Помогите, пожалуйста. Я новичок в angular.

HTML:

<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular.js"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <ul class="navigation">
    <li ng-repeat='category in fullTree.category[0]' ng-class='category.category_id' ng-click='dropmenu(category.category_id,category.level,category.has_child_category,$event);event.stopImmediatePropagation()'>
      <p>{{category.category_name}} <i class="ion-chevron-down"></i>
      </p>
    </li>
  </ul>
</body>

</html>

Сценарий:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, $sce, $compile) {
  $scope.name = 'World';
  $scope.html = "";

  $scope.htmlElement = function() {
    var html = "<input type='text' ng-model='html'></input>";
    return $sce.trustAsHtml(html);
  }

  $scope.fullTree = {
    "result": "true",
    "success": 1,
    "category": [
      [{
        "category_id": "prdcat01",
        "category_name": "Men",
        "level": "1",
        "higher_level_catg_no": "0",
        "total_level": "3",
        "has_child_category": "true",
        "total_product": "0"
      }, {
        "category_id": "prdcat02",
        "category_name": "Women",
        "level": "1",
        "higher_level_catg_no": "0",
        "total_level": "3",
        "has_child_category": "true",
        "total_product": "0"
      }, {
        "category_id": "prdcat03",
        "category_name": "Kids",
        "level": "1",
        "higher_level_catg_no": "0",
        "total_level": "1",
        "has_child_category": "false",
        "total_product": "0"
      }],
      [{
        "category_id": "cat01c01",
        "category_name": "Wrist Watch For Men",
        "level": "2",
        "higher_level_catg_no": "prdcat01",
        "has_child_category": "true",
        "total_product": "1"
      }, {
        "category_id": "cat02c01",
        "category_name": "Wrist Watch For Women",
        "level": "2",
        "higher_level_catg_no": "prdcat02",
        "has_child_category": "true",
        "total_product": "0"
      }, {
        "category_id": "cat01c02",
        "category_name": "Shirt for men",
        "level": "2",
        "higher_level_catg_no": "prdcat01",
        "has_child_category": "false",
        "total_product": "0"
      }, {
        "category_id": "cat02c02",
        "category_name": "Shirt For Women",
        "level": "2",
        "higher_level_catg_no": "prdcat02",
        "has_child_category": "false",
        "total_product": "0"
      }],
      [{
        "category_id": "cat0101c01",
        "category_name": "Fastrack Watch For Men",
        "level": "3",
        "higher_level_catg_no": "cat01c01",
        "has_child_category": "false",
        "total_product": "0"
      }, {
        "category_id": "cat0201c01",
        "category_name": "Fastrack Watch For Women",
        "level": "3",
        "higher_level_catg_no": "cat02c01",
        "has_child_category": "false",
        "total_product": "1"
      }, {
        "category_id": "cat0101c02",
        "category_name": "Casio watch for men",
        "level": "3",
        "higher_level_catg_no": "cat01c01",
        "has_child_category": "false",
        "total_product": "1"
      }]
    ],
    "msg": "Data retrieved successfuly"
  };

  $scope.dropmenu = function(category_id, level, has_child_category, $event) {
    $event.stopPropagation();

    $scope.dummy = [];

    for (var i = 0; i < $scope.fullTree.category[level].length; i++) {
      if ($scope.fullTree.category[level][i].higher_level_catg_no == category_id) {
        $scope.dummy.push($scope.fullTree.category[level][i]);
      }
    }

    alert(JSON.stringify($scope.dummy))

    var fieldHtml = "<ul class='navigation'><li ng-class={{category.category_id}} ng-repeat='category in dummy' ng-click='dropmenu(category.category_id,category.level,category.has_child_category,$event);event.stopPropagation()'><p>{{category.category_name}} <i class='ion-chevron-down'></i></p></li></ul>";

    var compiledElement = $compile(fieldHtml)($scope);

    $($event.target).closest("." + category_id).append(compiledElement);
  }
});
0
kavinhuh 10 Апр 2014 в 18:33

2 ответа

Лучший ответ

Вместо использования контроллеров для управления DOM лучше работать с директивами Angular - они созданы с учетом этой цели.

Вы можете заключить свой контент в директивы, как в примере ниже:

app.directive('collection', function () {
    return {
        restrict: "E",
        replace: true,
        scope: {
            collection: '=',
            catTree: '='
        },
        template: '<ul><member full-tree="catTree" cat-tree="catTree[category.level]" ng-repeat="category in collection track by category.category_id" category="category"></member></ul>'
    };
});

app.directive('member', function ($compile) {
    return {
        restrict: "E",
        replace: true,
        scope: {
            member: '=category',
            catTree: '=',
            fullTree: '='
        },
        template: '<li class="ng-hide" ng-show="showItem">{{member.category_name}}</li>',

        link: function (scope, element, attrs) {

            scope.currentTree = {};
            scope.currentTree.category = [];

            scope.showItem = (scope.member.level == '1');

            element.bind('click', function (ev) {
                jQuery(ev.target).siblings('ul').children('li').toggleClass('ng-hide');
                // Prevent Bubble
                return false;
            });

            if (scope.member.has_child_category) {
                for (var cat in scope.catTree) {
                    if (scope.catTree[cat].higher_level_catg_no == scope.member.category_id) {
                        scope.currentTree.category.push(scope.catTree[cat]);
                    }
                }               
                element.append('<collection collection="currentTree.category" cat-tree="fullTree"></collection>');
                $compile(element.contents())(scope);
            }           

        }
    };
});

Хотя эти директивы далеко не оптимизированы, их цель - продемонстрировать, как вы можете динамически добавлять контент в DOM и как вы можете манипулировать различными элементами.

Полный код можно протестировать здесь: http://plnkr.co/edit/W5K77XlvhcaAoYl0TEpJ?p=preview

Подробнее о директивах можно узнать здесь: http://www.sitepoint.com/practical -guide-angularjs-directives /

1
Gabriel 11 Апр 2014 в 15:04

Обновление для неизвестного количества уровней
Вы можете обобщить то, что я написал для каждого из 3 уровней, в шаблон и использовать его рекурсивно для обработки любого количества уровней подкатегорий.

Template.html:

<ul ng-show="$parent.category.expand" class="navigation" ng-init="level = $parent.level+1">
  <li ng-repeat="category in fullTree.category[level]" ng-if="category.higher_level_catg_no == $parent.category.category_id" ng-class="category.category_id">
    <p>{{category.category_name}}
      <i ng-click="category.expand = !category.expand" class="ion-chevron-down"></i>
    </p>
    <ng-include src="'template.html'" ng-if="fullTree.category[level+1]"></ng-include>
  </li>
</ul>

В index.html есть небольшое дублирование, которое, вероятно, можно было бы устранить, подумав над настройкой. Но это работает и не требует никаких манипуляций с DOM.

Вот обновленная демонстрация: http://plnkr.co/edit/DJ3hXHwYmf3n1LHAprerzWn?p= / а>


Оригинальный ответ для 3 уровня

Предлагаю прочитать этот вопрос: ​​«Мышление в AngularJS "есть ли у меня фон jQuery?

Вместо того, чтобы пытаться построить DOM в вашем контроллере, а затем возиться с компиляцией и вставкой его с помощью jQuery, вы можете вложить ng-repeat для создания структуры списка. Затем используйте ng-if для рендеринга подкатегорий при щелчке по родительской категории.

<ul class="navigation">
  <li ng-repeat="category in fullTree.category[0]" ng-class="category.category_id">
    <p>{{category.category_name}}
      <i ng-click="category.expand = !category.expand" class="ion-chevron-down"></i>
    </p>
    <ul ng-if="category.expand" class="navigation">
      <li ng-repeat="subcategory in fullTree.category[1]" ng-if="subcategory.higher_level_catg_no == category.category_id">
        <p>{{subcategory.category_name}}
          <i ng-click="subcategory.expand = !subcategory.expand" class="ion-chevron-down"></i>
        </p>
        <ul ng-if="subcategory.expand" class="navigation">
          <li ng-repeat="subcategory2 in fullTree.category[2]" ng-if="subcategory2.higher_level_catg_no == subcategory.category_id">
            <p>{{subcategory2.category_name}}
            </p>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

Вот рабочая демонстрация: http://plnkr.co/edit/lgYb8vFsFYpdXqKpreview

/ а>

2
Community 23 Май 2017 в 12:27