如何将控制器数据传递给 AngularJS 中的自定义指令?

How to pass controller data to a custom directive in AngularJS?

我在 AngularJS 中有一个自定义指令,我想从我的控制器向它传递一个变量。

控制器:

angular.
    module('orderOverview').
    component('orderOverview', {
        templateUrl: 'home-page/order-overview/order-overview.template.html',
        controller: ['Orders',
            function ControllerFunction(Orders) {
        var self = this;

        // Order Info
        Orders.getOverview().$promise.then(function(data) {
          self.LineItems = data;
        });
        // Order Info
      }
    ]
  });

指令

angular.
    module('myApp').
    directive('gvInitializeOrderStatus', function() {
    return {
      scope: {
        field: '@',
        myData: '='
      },
      link: function(scope, element) {
        console.log('field:', scope.field);
        console.log('data:', scope.myData);
      }
    }
    });

HTML

<div gv-initialize-order-status field="InquiryDone" myData="$ctrl.LineItems">
    <span class="tooltiptext">Inquiry</span>
</div>

当我加载页面时,field 记录正常,但是 data 未定义。

我已经尝试了很多方法,但如果它能让您了解我在想什么,这就是我的想法。

在同一模板的另一点,我将 ng-repeat 数据传递给一个指令就好了,但在这种情况下,我特别不想 ng-repeat

ng-repeat HTML 成功传递数据

<li ng-repeat="lineItem in $ctrl.LineItems">
    <div class="status-circle" 
         ng-click="toggleCircle($event, lineItem, 'InquiryDone')"
         field="InquiryDone" item="lineItem" gv-initialize-statuses>
        <span class="tooltiptext">Inquiry</span>
    </div>
</li>

在我的另一个指令 gv-initialize-statuses 中,我在我的 scope 对象中使用了相同的概念并且有类似 scope: { 'field': '=' } 的东西并且它工作得很好。

如何在不使用 ng-repeat 的情况下完成此操作?

如果您只想要指令中的数据,请执行此操作

Orders.getOverview().$promise.then(function(data) {
          self.LineItems = data;
          $rootScope.$broadcast('myData', data);
        });

并且在你的指令中用回调函数捕获这个事件

$scope.$on('myData', function(event, args) {

    var anyThing = args;
    // do what you want to do
});

在指令中

angular.
module('myApp').
directive('gvInitializeOrderStatus', function() {
return {
  scope: {
    field: '@',
    ngModel: '='     // <- access data with this (ngModel to ng-model in view)
  },
  link: function(scope, element) {
    console.log('field:', scope.field);
    console.log('data:', scope.ngModel);
  }
}
});

可见

<div gv-initialize-order-status field="InquiryDone" ng-model="$ctrl.LineItems">
  <span class="tooltiptext">Inquiry</span>
</div>

应避免与 = 的双向绑定

指令需要在link函数中使用$watch:

app.directive('gvInitializeOrderStatus', function() {
    return {
      scope: {
        field: '@',
        ̶m̶y̶D̶a̶t̶a̶:̶ ̶'̶=̶'̶
        myData: '<'
      },
      link: function(scope, element) {
        console.log('field:', scope.field);
        console.log('data:', scope.myData);
        scope.$watch('myData', function(value) {
            console.log('data:', scope.myData);
        });
      }
    }
});

ng-repeat 等指令自动使用观察者。

同样出于性能原因,应避免使用 = 进行双向绑定。使用 < 的单向绑定效率更高。


为了更高效的代码,在控制器中使用$onChanges life-cycle hook

app.directive('gvInitializeOrderStatus', function() {
    return {
      scope: {
        field: '@',
        ̶m̶y̶D̶a̶t̶a̶:̶ ̶'̶=̶'̶
        myData: '<'
      },
      bindToController: true,
      controllerAs: "$ctrl",
      controller: function() {
        console.log('field:', this.field);
        console.log('data:', this.myData);
        this.$onChanges = function(changes) {
            if (changes.myData)
                console.log('data:', changes.myData.currentValue);
            };
        });
      }
    }
});

这样做会使代码更高效,并且更容易迁移到 Angular 2+。


手表有不同等级:

ng-repeat指令实际上使用了$watchCollection.

指令可能需要使用$doCheck Life-Cycle hook

有关详细信息,请参阅

问题是$promise

当指令激活时,

self.LineItems 还没有准备好。这就是为什么数据是 undefined.

也许ng-if可以帮到你:

<div ng-if="$ctrl.LineItems" gv-initialize-order-status field="InquiryDone" myData="$ctrl.LineItems">
    <span class="tooltiptext">Inquiry</span>
</div>

希望这对您有所帮助。祝你好运!

因此,当我在文档中阅读有关 $compile 的内容时,我找到了一个有效的答案。我意识到你可以获得内插属性值,所以我从范围对象中删除了 myData 字段,而是通过 attrs 对象访问该值,就像这样。

指令

angular.
    module('myApp').
    directive('gvInitializeOrderStatus', function() {
    return {
      scope: {
        field: '@'
      },
      link: function(scope, element, attrs) {
        console.log('field:', scope.field);
        console.log('attrs:', attrs);
        attrs.$observe('lineItems', function(value) {
          console.log(value);
        })
      }
    }
    });

HTML

<div gv-initialize-order-status field="InquiryDone" lineItems="{{$ctrl.LineItems}}">
     <span class="tooltiptext">Inquiry</span>
</div>

请注意向 lineItems 属性添加的 {{ }}attrs.$observe 块还让我收到值更改的通知。