简体   繁体   English

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

[英]How to pass controller data to a custom directive in AngularJS?

I have a custom directive in AngularJS and I want to pass a variable to it from my controller. 我在AngularJS中有一个自定义指令,我想从控制器中将变量传递给它。

Controller: 控制器:

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
      }
    ]
  });

Directive 指示

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 的HTML

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

When I load the page, field logs fine, however data is undefined. 当我加载页面时, field记录很好,但是data未定义。

I've tried this a lot of ways, but this is how it should work in my mind if it gives you any idea of what I'm thinking of. 我已经尝试了很多方法,但是如果它可以让您对我的想法有所了解,这就是我应该想到的方法。

At another point in the same template I pass ng-repeat data to a directive just fine, but in this case I specifically don't want to ng-repeat 在同一模板的另一点上,我将ng-repeat数据传递给指令就好了,但是在这种情况下,我特别不想ng-repeat

ng-repeat HTML that successfully passed data 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>

In my other directive, gv-initialize-statuses , I use the same concept in my scope object and have something like scope: { 'field': '=' } and it works just fine. 在我的另一个指令gv-initialize-statuses ,我在我的scope对象中使用了相同的概念,并且具有类似scope: { 'field': '=' } ,并且效果很好。

How can I accomplish this without using ng-repeat? 如何不使用ng-repeat来完成此操作?

Two-way binding with = should be avoided 应避免与=双向绑定

The directive needs to use $watch in the link function: 该指令需要在链接函数中使用$ 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);
        });
      }
    }
});

Directives such as ng-repeat automatically use a watcher. 诸如ng-repeat指令会自动使用观察程序。

Also for performance reasons, two-way binding with = should be avoided. 同样出于性能原因,应避免与=双向绑定。 One-way binding with < is more efficient. <的单向绑定更有效。


For more efficient code, use the $onChanges life-cycle hook in the controller: 要获得更有效的代码,请在控制器中使用$onChanges生命周期挂钩

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);
            };
        });
      }
    }
});

Doing so will make the code more efficient and the migration to Angular 2+ easier. 这样做将使代码更高效,并且更容易迁移到Angular 2+。


There are different levels of watch: 有不同级别的监视:

The ng-repeat directive actually uses $watchCollection . ng-repeat指令实际上使用$ watchCollection

The directive may need to use the $doCheck Life-Cycle hook . 该指令可能需要使用$doCheck Life-Cycle hook

For more information, see 有关更多信息,请参见

Do this if you just want the data in your directive 如果只需要指令中的数据,请执行此操作

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

And in your directive just catch this event with callback function 并且在您的指令中只需使用回调函数捕获此事件

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

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

The problem is the $promise . 问题是$promise

self.LineItems is not ready when the directive get active. 指令激活时self.LineItems尚未准备就绪。 That's why data is undefined . 这就是为什么数据undefined的原因。

Maybe ng-if could helps you: 也许ng-if可以帮助您:

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

Hope this helps. 希望这可以帮助。 Good luck! 祝好运!

So I found an answer that works when I was reading about $compile in the docs. 因此,当我在文档中阅读有关$ compile时,我找到了一个有效的答案。 I realized you can get interpolated attribute values, so I removed the myData field from the scope object and instead accessed the value through the attrs object, like so. 我意识到可以获取插值的属性值,因此我从范围对象中删除了myData字段,而是像这样通过attrs对象访问了该值。

Directive 指示

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 的HTML

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

Notice the added {{ }} to the lineItems attribute. 请注意,在lineItems属性中添加了{{ }} The attrs.$observe block lets me get notices of changes to the value, as well. attrs.$observe块也使我可以知道该值的更改。

in directive 在指令中

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);
  }
}
});

in view 鉴于

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM