如何从作为可重用组件的指令公开API?

有一个angular度是一个可重用组件的指令,公开的API可以从控制器访问的最佳做法是什么? 所以当有多个组件的实例时,你可以从控制器访问

angular.directive('extLabel', function { return { scope: { name: '@', configObj: '=' }, link: function(scope, iElement, iAttrs) { // this could be and exposed method scope.changeLabel = function(newLabel) { scope.configObj.label = newLabel; } } } }); 

然后当有:

 <ext-label name="extlabel1" config-obj="label1"></ext-label> <ext-label name="extlabel2" config-obj="label2"></ext-label> <ext-label name="extlabel3" config-obj="label3"></ext-label> 

我怎样才能访问控制器中的extLabel2的scope.changeLabel?

是否有意义?

这对你有用吗?

 angular.directive('extLabel', function() { return { restrict: 'E', scope: { api: '=' }, link: function(scope, iElement, iAttrs) { scope.api = { doSomething: function() { }, doMore: function() { } }; } }; }); 

从包含父母

 <ext:label api="myCoolApi"></ext:label> 

并在控制器中

 $scope.myCoolApi.doSomething(); $scope.myCoolApi.doMore(); 

编写指令在我的Angular应用程序中实例化一个dygraph图表时遇到了这个问题。 尽pipe大部分的工作都可以通过数据绑定完成,但API的某些部分需要访问dygraph对象本身。 我解决了$emit()事件:

 'use strict'; angular.module('dygraphs', []); angular.module('dygraphs').directive('mrhDygraph', function ($parse, $q) { return { restrict: 'A', replace: true, scope: {data: '=', initialOptions: '@', options: '='}, link: function (scope, element, attrs) { var dataArrived = $q.defer(); dataArrived.promise.then(function (graphData) { scope.graph = new Dygraph(element[0], graphData, $parse(scope.initialOptions)(scope.$parent)); return graphData.length - 1; }).then(function(lastPoint) { scope.graph.setSelection(lastPoint); scope.$emit('dygraphCreated', element[0].id, scope.graph); }); var removeInitialDataWatch = scope.$watch('data', function (newValue, oldValue, scope) { if ((newValue !== oldValue) && (newValue.length > 0)) { dataArrived.resolve(newValue); removeInitialDataWatch(); scope.$watch('data', function (newValue, oldValue, scope) { if ((newValue !== oldValue) && (newValue.length > 0)) { var selection = scope.graph.getSelection(); if (selection > 0) { scope.graph.clearSelection(selection); } scope.graph.updateOptions({'file': newValue}); if ((selection >= 0) && (selection < newValue.length)) { scope.graph.setSelection(selection); } } }, true); scope.$watch('options', function (newValue, oldValue, scope) { if (newValue !== undefined) { scope.graph.updateOptions(newValue); } }, true); } }, true); } }; }); 

dygraphCreated事件的参数包括元素id以及dygraph对象,允许在同一范围内使用多个dygraph。

我喜欢Andrej's,并且经常使用这个模式,但是我想提出一些改变

 angular.directive('extLabel', function { return { scope: { api: '=?', configObj: '=' }, // A controller, and not a link function. From my understanding, // try to use the link function for things that require post link actions // (for example DOM manipulation on the directive) controller: ['$scope', function($scope) { // Assign the api just once $scope.api = { changeLabel: changeLabel }; function changeLabel = function(newLabel) { $scope.configObj.label = newLabel; } }] } }); <ext-label name="extlabel1" config-obj="label1"></ext-label> <ext-label api="label2api" name="extlabel2" config-obj="label2"></ext-label> <ext-label name="extlabel3" config-obj="label3"></ext-label> 

当然在控制器label2api.changeLabel('label')

在我看来,一个家长不应该访问一个儿童范围。 你怎么知道哪一个使用,哪一个不使用。 控制者只能访问他自己的范围或他的父范围。 否则打破封装。

如果你想改变你的标签,你真正需要做的就是改变label1 / label2 / label3variables的值。 启用数据绑定后,它应该可以工作。 在你的指令中,如果每次改变都需要一些逻辑,你可以$watch它。

 angular.directive('extLabel', function { return { scope: { name: '@', configObj: '=' }, link: function(scope, iElement, iAttrs) { scope.$watch("configObj", function() { // Do whatever you need to do when it changes }); } } }); 

使用这些指令你想去的prev和下一个元素:

 <carousel> <slide> <button class="action" carousel-next> Next </button> <button class="action" carousel-prev> Back </button> </slide> </carousel> .directive('carouselNext', function () { return { restrict: 'A', scope: {}, require: ['^carousel'], link: function (scope, element, attrs, controllers) { var carousel = controllers[0]; function howIsNext() { if ((carousel.indexOfSlide(carousel.currentSlide) + 1) === carousel.slides.length) { return 0; } else { return carousel.indexOfSlide(carousel.currentSlide) + 1; } } element.bind('click', function () { carousel.select(carousel.slides[howIsNext()]); }); } }; }) .directive('carouselPrev', function () { return { restrict: 'A', scope: {}, require: ['^carousel'], link: function (scope, element, attrs, controllers) { var carousel = controllers[0]; function howIsPrev() { if (carousel.indexOfSlide(carousel.currentSlide) === 0) { return carousel.slides.length; } else { return carousel.indexOfSlide(carousel.currentSlide) - 1; } } element.bind('click', function () { carousel.select(carousel.slides[howIsPrev()]); }); } }; })