Angularjs在指令中与编译器属性一起出现问题

时间:2013-07-19 16:39:51

标签: angularjs angularjs-directive angularjs-ng-repeat

我正在学习angularjs,我正在训练如何构建一个可重用的指令。

问题是它适用于包含1个元素但不包含2个或更多元素的数组。

html标记只是:<breadcrumb></breadcrumb>,以防万一,按预期呈现。但是,我需要手动执行“替换:true”会做什么。

错误是:父级为空

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

但是我的情况很奇怪,因为<inner ng-repeat>里面有<breadcrumb>这是另一个内部指令而不是普通标签,这就是为什么替换不起作用而我需要手动完成的原因。

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

obs:我试​​着在“link:”和“compile:”逻辑中做同样的错误......

[编辑] 我可以使代码有效,但是,我无法删除<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);
                };
            }
        };
    }
]);

2 个答案:

答案 0 :(得分:2)

您可以在inner指令中删除您的编译功能并设置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的{​​{1}}将按预期在父作用域中定义。这是首选方式,您甚至可以使用不同的内部模板(就像我使用ng-repeat标记一样)。如果是这种情况,您甚至可以不使用<i>并对ng-repeat元素进行硬编码:

inner

这是一个有效的Plnker

答案 1 :(得分:0)

我能够重建它。

完整代码在此处:http://plnkr.co/ZQOHqao8aqksbVjGQTHj

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

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