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

Saf*_*afa 35 angularjs angularjs-directive angularjs-scope

如果有一个可重用组件的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;
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

然后当有:

<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>
Run Code Online (Sandbox Code Playgroud)

如何在控制器中访问extLabel2的scope.changeLabel?

是否有意义?

And*_*rin 22

这对你有用吗?

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

来自包含父母

<ext:label api="myCoolApi"></ext:label>
Run Code Online (Sandbox Code Playgroud)

在控制器中

$scope.myCoolApi.doSomething();
$scope.myCoolApi.doMore();
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的方法,但有些注意事项 - 1.你必须在指令中取消订阅api的手表,否则你会发现自己处于无限循环中.2.因为一个人并不总是想要访问api,你应该将api定义为"=?" (4认同)
  • 我对此的关注是,当您尝试使用api时,不一定要定义api.你会如何确保这一点? (2认同)

Val*_*l3y 6

我喜欢Andrej并定期使用这种模式,但我想建议一些改变

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>
Run Code Online (Sandbox Code Playgroud)

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


Max*_*Max 5

在编写一个指令来实现我的Angular应用程序中的dygraph图时,我遇到了这个问题.尽管大多数工作都可以通过数据绑定完成,但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);
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

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


Ben*_*lay 2

在我看来,父级不应该访问子级范围。您如何知道该使用哪一个以及不使用哪一个。控制器应该只访问他自己的作用域或他的父作用域。否则它会破坏封装。

如果您想更改标签,您真正需要做的就是更改 label1/label2/label3 变量值。启用数据绑定后,它应该可以工作。在你的指令中,$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
            });
        }
    }  
});
Run Code Online (Sandbox Code Playgroud)

  • 我相信相反的方式更容易被接受。父级可以访问子级,使子级保持通用。如果子元素访问父元素,则它不能在不同的父元素之间重用。 (3认同)