我有一个指令,这是代码:

.directive('map', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        link: function($scope, element, attrs) {

            var center = new google.maps.LatLng(50.1, 14.4); 
            $scope.map_options = {
                zoom: 14,
                center: center,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            // create map
            var map = new google.maps.Map(document.getElementById(attrs.id), $scope.map_options);
            var dirService= new google.maps.DirectionsService();
            var dirRenderer= new google.maps.DirectionsRenderer()

            var showDirections = function(dirResult, dirStatus) {
                if (dirStatus != google.maps.DirectionsStatus.OK) {
                    alert('Directions failed: ' + dirStatus);
                    return;
                  }
                  // Show directions
                dirRenderer.setMap(map);
                //$scope.dirRenderer.setPanel(Demo.dirContainer);
                dirRenderer.setDirections(dirResult);
            };

            // Watch
            var updateMap = function(){
                dirService.route($scope.dirRequest, showDirections); 
            };    
            $scope.$watch('dirRequest.origin', updateMap);

            google.maps.event.addListener(map, 'zoom_changed', function() {
                $scope.map_options.zoom = map.getZoom();
              });

            dirService.route($scope.dirRequest, showDirections);  
        }
    }
})

我想在用户操作上调用updateMap()。操作按钮不在指令上。

从控制器调用updateMap()的最佳方法是什么?


当前回答

你可以把方法名告诉指令来定义你想从控制器调用哪个,但没有隔离作用域,

angular.module("app", []) .directive("palyer", [ function() { return { restrict: "A", template:'<div class="player"><span ng-bind="text"></span></div>', link: function($scope, element, attr) { if (attr.toPlay) { $scope[attr.toPlay] = function(name) { $scope.text = name + " playing..."; } } } }; } ]) .controller("playerController", ["$scope", function($scope) { $scope.clickPlay = function() { $scope.play('AR Song'); }; } ]); .player{ border:1px solid; padding: 10px; } <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app"> <div ng-controller="playerController"> <p>Click play button to play <p> <p palyer="" to-play="play"></p> <button ng-click="clickPlay()">Play</button> </div> </div>

其他回答

使用范围。将被调用的函数关联到指令函数

angular.module('myApp', [])
.controller('MyCtrl',['$scope',function($scope) {

}])
.directive('mydirective',function(){
 function link(scope, el, attr){
   //use scope.$parent to associate the function called to directive function
   scope.$parent.myfunction = function directivefunction(parameter){
     //do something
}
}
return {
        link: link,
        restrict: 'E'   
      };
});

在HTML中

<div ng-controller="MyCtrl">
    <mydirective></mydirective>
    <button ng-click="myfunction(parameter)">call()</button>
</div>

假设动作按钮使用与指令相同的控制器$scope,只需在链接函数内的$scope上定义函数updateMap。然后,当单击操作按钮时,控制器可以调用该函数。

<div ng-controller="MyCtrl">
    <map></map>
    <button ng-click="updateMap()">call updateMap()</button>
</div>
app.directive('map', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        link: function($scope, element, attrs) {
            $scope.updateMap = function() {
                alert('inside updateMap()');
            }
        }
    }
});

小提琴


根据@FlorianF的评论,如果指令使用孤立的作用域,事情就更复杂了。这里有一种让它工作的方法:给map指令添加一个set-fn属性,它将在控制器上注册指令函数:

<map set-fn="setDirectiveFn(theDirFn)"></map>
<button ng-click="directiveFn()">call directive function</button>
scope: { setFn: '&' },
link: function(scope, element, attrs) {
    scope.updateMap = function() {
       alert('inside updateMap()');
    }
    scope.setFn({theDirFn: scope.updateMap});
}
function MyCtrl($scope) {
    $scope.setDirectiveFn = function(directiveFn) {
        $scope.directiveFn = directiveFn;
    };
}

小提琴

如何在页面控制器中获取指令的控制器:

write a custom directive to get the reference to the directive controller from the DOM element: angular.module('myApp') .directive('controller', controller); controller.$inject = ['$parse']; function controller($parse) { var directive = { restrict: 'A', link: linkFunction }; return directive; function linkFunction(scope, el, attrs) { var directiveName = attrs.$normalize(el.prop("tagName").toLowerCase()); var directiveController = el.controller(directiveName); var model = $parse(attrs.controller); model.assign(scope, directiveController); } } use it in the page controller's html: <my-directive controller="vm.myDirectiveController"></my-directive> Use the directive controller in the page controller: vm.myDirectiveController.callSomeMethod();

注意:给出的解决方案只适用于元素指令的控制器(标签名用于获取所需指令的名称)。

你可以把方法名告诉指令来定义你想从控制器调用哪个,但没有隔离作用域,

angular.module("app", []) .directive("palyer", [ function() { return { restrict: "A", template:'<div class="player"><span ng-bind="text"></span></div>', link: function($scope, element, attr) { if (attr.toPlay) { $scope[attr.toPlay] = function(name) { $scope.text = name + " playing..."; } } } }; } ]) .controller("playerController", ["$scope", function($scope) { $scope.clickPlay = function() { $scope.play('AR Song'); }; } ]); .player{ border:1px solid; padding: 10px; } <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app"> <div ng-controller="playerController"> <p>Click play button to play <p> <p palyer="" to-play="play"></p> <button ng-click="clickPlay()">Play</button> </div> </div>

如果你想使用隔离作用域,你可以使用控制器作用域变量的双向绑定=来传递一个控制对象。你也可以用相同的控制对象控制页面上相同指令的几个实例。

angular.module('directiveControlDemo', []) .controller('MainCtrl', function($scope) { $scope.focusinControl = {}; }) .directive('focusin', function factory() { return { restrict: 'E', replace: true, template: '<div>A:{{internalControl}}</div>', scope: { control: '=' }, link: function(scope, element, attrs) { scope.internalControl = scope.control || {}; scope.internalControl.takenTablets = 0; scope.internalControl.takeTablet = function() { scope.internalControl.takenTablets += 1; } } }; }); <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="directiveControlDemo"> <div ng-controller="MainCtrl"> <button ng-click="focusinControl.takeTablet()">Call directive function</button> <p> <b>In controller scope:</b> {{focusinControl}} </p> <p> <b>In directive scope:</b> <focusin control="focusinControl"></focusin> </p> <p> <b>Without control object:</b> <focusin></focusin> </p> </div> </div>