可能的Angular属性指令错误

Possible Angular attribute directive bug?

本文关键字:指令 错误 属性 Angular      更新时间:2023-09-26

我试图创建一个Angular指令,这只是一个HTML属性(my-directive)。这个指令使用了一些输入属性(text, length)。

<li my-directive text="first" length="6"></li>

只要我用一次,一切都很好。但是我想多次使用它,用于列表项:

<ul>
  <li my-directive text="first" length="elements[0].len"></li>
  <li my-directive text="second" length="elements[1].len"></li>
  <li my-directive text="third" length="elements[2].len"></li>
  <li my-directive text="fourth" length="elements[3].len"></li>
</ul>

这时我遇到了一个奇怪的行为:每个列表项显示最后一个项的属性。我检查了一下,指令控制器收到了不同的值。但是,只显示最后一个。

我很确定以前有人碰到过这个,但是我找不到任何相关的。

Plunkr这里

更新:

看起来这个问题可以用ng-repeat来解决,但我宁愿不使用它。

为指令使用隔离作用域将解决问题

http://plnkr.co/edit/pwfbShFYLPMHlSLf48ng?p =

预览
.directive('myDirective', function () {
    return {
      restrict: 'A',
      bindToController: {
        // text: '@text',
        length: '='
      },
      scope: {},
      controller: function() {
        var ctrl = this;
        return ctrl;
      },
      controllerAs: 'ctrl',
      template: '{{ ctrl.text }} - {{ ctrl.length }}'
    }
  });

我个人认为这可以解释为一个bug,但老实说,这更像是bindToController和指令工作的结果。

这个问题可以被描述为范围问题。默认情况下,指令不会创建一个孤立的作用域,除非你告诉它这样做。根据angularjs的文档,使用bindToController的bindToController默认情况下也不会创建一个作用域,所以你的所有指令都是通过逻辑事故来做的,将你的控制器作用域绑定在父作用域(即myController)上。例如,如果你在一个链接函数上添加一个console.log(scope),你会看到每个指令的所有作用域都是相同的。

  link: function (scope) { console.log(scope);}

然而,不管在不了解这种行为的情况下处理这个问题可能会有问题,它可以通过创建一个孤立的作用域来完成,就像下面的例子一样,并使用bindToController特性的布尔版本。

  bindToController: true,
  scope: {
    text: '@text',
    length: '='
  }

完整的片段:

  angular.module('myApp', [])
    .controller('myController', function($scope) {
      $scope.test = 'here';
      $scope.elements = [{
        len: 7
      }, {
        len: 13
      }, {
        len: 12
      }, {
        len: 35
      }, ]
    })
    .directive('myDirective', function() {
      return {
        restrict: 'A',
        bindToController: true,
        scope: {
          text: '@text',
          length: '='
        },
        controller: function() {
          var ctrl = this;
          return ctrl;
        },
        controllerAs: 'ctrl',
        template: '{{ ctrl.text }} - {{ ctrl.length }}'
      }
    });
  angular.element(document).ready(function() {
    angular.bootstrap(document, ['myApp']);
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-controller="myController">
  {{ test }}
  <br>
  <ul>
    <li my-directive text="first" length="elements[0].len"></li>
    <li my-directive text="second" length="elements[1].len"></li>
    <li my-directive text="third" length="elements[2].len"></li>
    <li my-directive text="fourth" length="elements[3].len"></li>
  </ul>
</div>

这可能是一个解决方案。

<body ng-app="myApp">
    <div ng-controller="myController">
      {{ test }}
      <ul>
        <li ng-repeat="elm in elements" my-directive text="{{elm.text}}" length="elm.len"></li>
      </ul>
    </div>
  </body>

和script.js

$scope.elements = [
         {
           text:'first',
           len: 7
         },
         {
           text:'second',
           len: 13
         },
         {
           text:'third',
           len: 12
         },
         {
           text:'fourth',
           len: 35
         },
      ]