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

.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()的最佳方法是什么?


当前回答

有点晚了,但这是一个具有隔离作用域和在指令中调用函数的“事件”的解决方案。这个解决方案的灵感来自satchmorun的这篇SO帖子,并添加了一个模块和一个API。

//Create module
var MapModule = angular.module('MapModule', []);

//Load dependency dynamically
angular.module('app').requires.push('MapModule');

创建一个API来与指令通信。addUpdateEvent将一个事件添加到事件数组中,updateMap调用每个事件函数。

MapModule.factory('MapApi', function () {
    return {
        events: [],

        addUpdateEvent: function (func) {
            this.events.push(func);
        },

        updateMap: function () {
            this.events.forEach(function (func) {
                func.call();
            });
        }
    }
});

(也许你必须添加功能来删除事件。)

在指令中设置MapAPI的引用并添加$scope。MapApi. updateMap作为事件。updateMap被调用。

app.directive('map', function () {
    return {
        restrict: 'E', 
        scope: {}, 
        templateUrl: '....',
        controller: function ($scope, $http, $attrs, MapApi) {

            $scope.api = MapApi;

            $scope.updateMap = function () {
                //Update the map 
            };

            //Add event
            $scope.api.addUpdateEvent($scope.updateMap);

        }
    }
});

在“主”控制器中添加MapApi引用,并调用MapApi. updatemap()来更新映射。

app.controller('mainController', function ($scope, MapApi) {

    $scope.updateMapButtonClick = function() {
        MapApi.updateMap();    
    };
}

其他回答

也许这不是最好的选择,但你可以使用angular.element("#element"). isolatescope()或$("#element"). isolatescope()来访问指令的作用域和/或控制器。

下面的解决方案将是有用的,当你有'控制器As'格式的控制器(父控制器和指令(隔离))

有人可能会觉得这很有用,

指令:

var directive = {
        link: link,
        restrict: 'E',
        replace: true,
        scope: {
            clearFilters: '='
        },
        templateUrl: "/temp.html",
        bindToController: true, 
        controller: ProjectCustomAttributesController,
        controllerAs: 'vmd'
    };
    return directive;

    function link(scope, element, attrs) {
        scope.vmd.clearFilters = scope.vmd.SetFitlersToDefaultValue;
    }
}

控制器:

function DirectiveController($location, dbConnection, uiUtility) {
  vmd.SetFitlersToDefaultValue = SetFitlersToDefaultValue;

function SetFitlersToDefaultValue() {
           //your logic
        }
}

HTML代码:

      <Test-directive clear-filters="vm.ClearFilters"></Test-directive>
    <a class="pull-right" style="cursor: pointer" ng-click="vm.ClearFilters()"><u>Clear</u></a> 
//this button is from parent controller which will call directive controller function

有点晚了,但这是一个具有隔离作用域和在指令中调用函数的“事件”的解决方案。这个解决方案的灵感来自satchmorun的这篇SO帖子,并添加了一个模块和一个API。

//Create module
var MapModule = angular.module('MapModule', []);

//Load dependency dynamically
angular.module('app').requires.push('MapModule');

创建一个API来与指令通信。addUpdateEvent将一个事件添加到事件数组中,updateMap调用每个事件函数。

MapModule.factory('MapApi', function () {
    return {
        events: [],

        addUpdateEvent: function (func) {
            this.events.push(func);
        },

        updateMap: function () {
            this.events.forEach(function (func) {
                func.call();
            });
        }
    }
});

(也许你必须添加功能来删除事件。)

在指令中设置MapAPI的引用并添加$scope。MapApi. updateMap作为事件。updateMap被调用。

app.directive('map', function () {
    return {
        restrict: 'E', 
        scope: {}, 
        templateUrl: '....',
        controller: function ($scope, $http, $attrs, MapApi) {

            $scope.api = MapApi;

            $scope.updateMap = function () {
                //Update the map 
            };

            //Add event
            $scope.api.addUpdateEvent($scope.updateMap);

        }
    }
});

在“主”控制器中添加MapApi引用,并调用MapApi. updatemap()来更新映射。

app.controller('mainController', function ($scope, MapApi) {

    $scope.updateMapButtonClick = function() {
        MapApi.updateMap();    
    };
}

尽管将对象暴露在指令的孤立作用域上以方便与之通信可能很有吸引力,但这样做可能会导致令人困惑的“意大利面条”代码,特别是当你需要通过几个级别(控制器、指令、嵌套指令等)链接这种通信时。

我们最初是沿着这条路走的,但经过更多的研究后发现,它更有意义,并导致更可维护和可读的代码,以公开事件和属性,指令将通过服务进行通信,然后在指令中的服务属性上使用$watch或任何其他控件,这些控件需要对通信的这些变化做出反应。

这种抽象与AngularJS的依赖注入框架配合得非常好,因为你可以将服务注入到任何需要对这些事件做出反应的项中。如果你看一下Angular.js文件,你会发现里面的指令也以这种方式使用services和$watch,它们不会在孤立的作用域中公开事件。

最后,如果你需要在相互依赖的指令之间通信,我建议在这些指令之间共享一个控制器作为通信手段。

AngularJS的维基最佳实践也提到了这个:

Only use .$broadcast(), .$emit() and .$on() for atomic events Events that are relevant globally across the entire app (such as a user authenticating or the app closing). If you want events specific to modules, services or widgets you should consider Services, Directive Controllers, or 3rd Party Libs $scope.$watch() should replace the need for events Injecting services and calling methods directly is also useful for direct communication Directives are able to directly communicate with each other through directive-controllers

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

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>