AngularJS - ngRepeat is applied double times when

2019-07-09 09:12发布

I want this

$scope.name = 'Angular';
$scope.list = ['foo: {{name}}', 'bar: {{name}}'];

<div ng-repeat="template in list" compile="template"></div>

to be

<div real="foo: Angular"></div>
<div real="bar: Angular"></div>

So i use $compile:

$compileProvider.directive('compile', function ($compile) {
    return function (scope, element, attrs) {
        scope.$watch(
            function (scope) {
                return scope.$eval(attrs.compile);
            },
            function (value) {
                //element.html(value);
                //$compile(element.contents())(scope);

                element.attr("real", value);
                element.removeAttr("compile");
                $compile(element)(scope);
            }
        );
    };
})

but, it output:

<div real="foo: Angular"></div>
<div real="foo: Angular"></div>
<div real="bar: Angular"></div>
<div real="bar: Angular"></div>

so what's the problem ?

Demo: http://plnkr.co/edit/OdnriGpd7eMBtfp2u1b2?p=preview

2条回答
Emotional °昔
2楼-- · 2019-07-09 09:55

Alternatively, you can use the pre link function : http://plnkr.co/edit/VIOAX1akTPF68DYxZQcQ

angular.module('demo', [], function($compileProvider) {
  $compileProvider.directive('compile', function($compile) {
    return {
      restrict:'A',
      compile: function(celement, cattrs) {
        return{
          pre: function(scope,element,attrs){
            var attribute = scope[attrs.compile];
            element.attr('real',attribute);
            element.removeAttr('compile');
            $compile(element)(scope);
          },
          post: function(scope,ielmt,iattrs){

          }
        }
      }
    };
  })
});

function Ctrl($scope) {
  $scope.name = 'Angular';
  $scope.list = ['foo: {{name}}', 'bar: {{name}}'];
}
查看更多
叼着烟拽天下
3楼-- · 2019-07-09 10:03

Try this instead:

<div ng-repeat="template in list">
    <div compile="template"></div>
</div>

DEMO

Explanation:

When you put your directive on the same element with ng-repeat and call $compile(element)(scope);, your element is recompiled including the ng-repeat, causing the ng-repeat to run one more time. When I also remove the ng-repeat in the directive, it works:

  element.attr("real", value);
  element.removeAttr("compile");
  element.removeAttr("ng-repeat");
  $compile(element)(scope);

DEMO

This solution is not recommended because we hard-code the element.removeAttr("ng-repeat");

Remember to also apply priority:1500 and terminal:true to the directive to avoid compiling again after angular has compiled the element:

$compileProvider.directive('compile', function($compile) {
    return {
      priority:1500,
      terminal:true,
      link: function(scope, element, attrs) {
        scope.$watch(
          function(scope) {
            return scope.$eval(attrs.compile);
          },
          function(value) {
            //element.html(value);
            //$compile(element.contents())(scope);

            element.attr("real", value);
            element.removeAttr("compile");
            $compile(element)(scope);
          }
        );
      }
    };
  });

For more information about these 2 settings. Check out Add directives from directive in AngularJS

查看更多
登录 后发表回答