2

我正在学习 AngularJS,并且正在培训如何构建可重用指令。

问题是它适用于具有一个元素的数组,但不适用于两个或更多元素。

HTML 标记只是:<breadcrumb></breadcrumb>在这种情况下,按预期呈现。但是,我需要手动执行“replace:true”会执行的操作。

错误是:parent 是 null

我用尽了所有谷歌搜索来寻找一个例子。

但我的情况很特殊,因为<inner ng-repeat>内部<breadcrumb>是另一个内部指令而不是普通标签,这就是替换不起作用的原因,我需要手动执行。

存在与“动态模板加载...”相关的问题

OBS:我尝试在“链接:”和“编译:”中都做逻辑,同样的错误......


我可以使代码工作,但是,我无法像自动删除<inner>标签那样删除标签transclude

现在输出几乎是完美的,我只需要删除<inner>,但直到现在还没有运气。我试图替换元素标签,但仍然没有运气。

<ul class="breadcrumb">

    <!-- I want to remove this <inner> and leave <li> alone! -->
    <inner data-ng-repeat="_item in items track by $index" class="ng-scope">
        <li class="ng-scope"><a href="#" class="ng-binding">1</a>
        </li>
    </inner>

    <!-- remove for clarity -->
</ul>
var myModule = angular.module("myModule", []);

myModule.directive('breadcrumb', function($timeout) {

    "use strict";

    var directiveDefinitionObject = {
        template: '<ul class="breadcrumb"><inner data-ng-repeat="_item in items track by $index"></inner></ul>',
        replace: true,
        // transclude: true,
        restrict: 'E',
        scope: {},
        controller: ["$scope", "$element", "$attrs", "$transclude", controller],
        link: ["scope", "iElement", "iAttrs", link]
    };

    function link(scope, iElement, iAttrs) {
        scope.addNewItem = function(new_item) {
            scope._push(new_item);
        }
    }

    function controller($scope, $element, $attrs, $transclude) {
        $scope.items = [1, 2, 3, 4, 5];

        $scope._push = function(item) {
            $scope.items.push(item);
        };

        $scope._pop = function() {
            $scope.items.pop();
        };

        $scope.is_last = function(item) {
            return $scope.items.indexOf(item) == ($scope.items.length - 1);
        }
    }

    return directiveDefinitionObject;
});

myModule.directive("inner", ["$compile",
    function($compile) {

        "use strict";

        function getItemTemplate(index) {
            return '<li><a href="#">{{ _item }}</a></li>';
        }

        return {
            require: "^breadcrumb",
            restrict: "E",
            compile: function compile(tElement, tAttrs)
            {
                return function postLink(scope, iElement, iAttrs)
                {
                    iElement.html(getItemTemplate(0));

                    $compile(iElement.contents())(scope);
                };
            }
        };
    }
]);
4

2 回答 2

2

您可以在inner指令和 set中删除您的编译功能,因为正如您所说replace: true,它只是在模拟 的默认行为。replace所以你inner的指令会变成:

myModule.directive("inner", ["$compile",
  function($compile) {

    "use strict";

    return {
      replace: true
      require: "^breadcrumb",
      restrict: "E",
      template: '<li><a href="#">{{ _item }}</a></li>'
    };
  }
]);

但是你有一个问题,你的items数组被定义到你的breadcrumb指令中,什么是错的,不会让你让它可重用。您可以在scope定义时将其绑定,如下所示:

<breadcrumb items="someItemsArrayFromParentScope"></breadcrumb>
...directive('breadcrumb', function() {
   ...

   return {
     ...
     scope: {
       items: '='
     }
   }
});

这将在来自父级和内部小部件范围的数组之间创建一个双向绑定。但更进一步,您可能希望让用户定义 的内部元素,breadcrumb如下所示:

myModule.directive('breadcrumb', function($timeout) {
  var directiveDefinitionObject = {
    template: '<ul class="breadcrumb" ng-transclude></ul>',
    replace: true,
    transclude: true,
    restrict: 'E',
    scope: {},
    controller: ["$scope", "$element", "$attrs", "$transclude", controller]
  };

  function controller($scope, $element, $attrs, $transclude) {
    $scope.addNewItem = function(new_item) {
        $scope._push(new_item);
    }

    $scope._push = function(item) {
        $scope.items.push(item);
    };

    $scope._pop = function() {
        $scope.items.pop();
    };

    $scope.is_last = function(item) {
        return $scope.items.indexOf(item) == ($scope.items.length - 1);
    }
  }

  return directiveDefinitionObject;
});

myModule.directive("inner", function($compile) {
    return {
        require: "^breadcrumb",
        restrict: "E",
        template: '<li><a href="#" ng-transclude></a></li>',
        replace: true,
        transclude: true
    };
  }
);

在您的 html 中,您将附带:

<breadcrumb>
  <inner ng-repeat="item in items"><i>{{item}}</i></inner>
</breacrumb>

诀窍是ng-transclude模板内的指令。它只是获取元素的内容并将其“移动”到标记为的元素内部ng-transclude并将其链接到父范围,这太棒了,因为您可以对基于父范围的项目进行动态命名。items例如,的ng-repeat将按预期在父范围中定义。这是首选方式,您甚至可以使用不同的内部模板(就像我对<i>标签所做的那样)。如果是这种情况,您甚至可以不使用ng-repeat和硬编码inner元素:

<!-- language: lang-html -->

<breadcrumb>
  <inner>First Path</inner>
  <inner>Second Path: {{someParentScopeVariable}}</inner>
</breacrumb>

这是一个工作Plnker

于 2013-07-20T14:00:27.537 回答
0

我能够重建它。

自从我第一次尝试以来,我学到了很多东西。

解决方案被简化了,因为动态模板处理起来很垃圾,因为ng-repeat不会重绘整个数组。所以,我按照自己的方式做了,这是一个干净的解决方案。

于 2013-09-09T22:46:12.627 回答