How to call a method defined in an AngularJS directive?

前端 未结 13 1072
萌比男神i
萌比男神i 2020-11-22 14:39

I have a directive, here is the code :

.directive(\'map\', function() {
    return {
        restrict: \'E\',
        replace: true,
        template: \'<         


        
相关标签:
13条回答
  • 2020-11-22 15:24

    TESTED Hope this helps someone.

    My simple approach (Think tags as your original code)

    <html>
    <div ng-click="myfuncion"> 
    <my-dir callfunction="myfunction">
    </html>
    
    <directive "my-dir">
    callfunction:"=callfunction"
    link : function(scope,element,attr) {
    scope.callfunction = function() {
     /// your code
    }
    }
    </directive>
    
    0 讨论(0)
  • 2020-11-22 15:30

    You can specify a DOM attribute that can be used to allow the directive to define a function on the parent scope. The parent scope can then call this method like any other. Here's a plunker. And below is the relevant code.

    clearfn is an attribute on the directive element into which the parent scope can pass a scope property which the directive can then set to a function that accomplish's the desired behavior.

    <!DOCTYPE html>
    <html ng-app="myapp">
      <head>
        <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
        <link rel="stylesheet" href="style.css" />
        <style>
          my-box{
            display:block;
            border:solid 1px #aaa;
            min-width:50px;
            min-height:50px;
            padding:.5em;
            margin:1em;
            outline:0px;
            box-shadow:inset 0px 0px .4em #aaa;
          }
        </style>
      </head>
      <body ng-controller="mycontroller">
        <h1>Call method on directive</h1>
        <button ng-click="clear()">Clear</button>
        <my-box clearfn="clear" contentEditable=true></my-box>
        <script>
          var app = angular.module('myapp', []);
          app.controller('mycontroller', function($scope){
          });
          app.directive('myBox', function(){
            return {
              restrict: 'E',
              scope: {
                clearFn: '=clearfn'
              },
              template: '',
              link: function(scope, element, attrs){
                element.html('Hello World!');
                scope.clearFn = function(){
                  element.html('');
                };
              }
            }
          });
        </script>
      </body>
    </html>
    
    0 讨论(0)
  • 2020-11-22 15:31

    If you want to use isolated scopes you can pass a control object using bi-directional binding = of a variable from the controller scope. You can also control also several instances of the same directive on a page with the same control object.

    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>

    0 讨论(0)
  • 2020-11-22 15:31

    How to get a directive's controller in a page controller:

    1. 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);
          }
      }
      
    2. use it in the page controller's html:

      <my-directive controller="vm.myDirectiveController"></my-directive>
      
    3. Use the directive controller in the page controller:

      vm.myDirectiveController.callSomeMethod();
      

    Note: the given solution works only for element directives' controllers (tag name is used to get the name of the wanted directive).

    0 讨论(0)
  • 2020-11-22 15:32

    To be honest, I was not really convinced with any of the answers in this thread. So, here's are my solutions:

    Directive Handler(Manager) Approach

    This method is agnostic to whether the directive's $scope is a shared one or isolated one

    A factory to register the directive instances

    angular.module('myModule').factory('MyDirectiveHandler', function() {
        var instance_map = {};
        var service = {
            registerDirective: registerDirective,
            getDirective: getDirective,
            deregisterDirective: deregisterDirective
        };
    
        return service;
    
        function registerDirective(name, ctrl) {
            instance_map[name] = ctrl;
        }
    
        function getDirective(name) {
            return instance_map[name];
        }
    
        function deregisterDirective(name) {
            instance_map[name] = null;
        }
    });
    

    The directive code, I usually put all the logic that doesn't deal with DOM inside directive controller. And registering the controller instance inside our handler

    angular.module('myModule').directive('myDirective', function(MyDirectiveHandler) {
        var directive = {
            link: link,
            controller: controller
        };
    
        return directive;
    
        function link() {
            //link fn code
        }
    
        function controller($scope, $attrs) {
            var name = $attrs.name;
    
            this.updateMap = function() {
                //some code
            };
    
            MyDirectiveHandler.registerDirective(name, this);
    
            $scope.$on('destroy', function() {
                MyDirectiveHandler.deregisterDirective(name);
            });
        }
    })
    

    template code

    <div my-directive name="foo"></div>
    

    Access the controller instance using the factory & run the publicly exposed methods

    angular.module('myModule').controller('MyController', function(MyDirectiveHandler, $scope) {
        $scope.someFn = function() {
            MyDirectiveHandler.get('foo').updateMap();
        };
    });
    

    Angular's approach

    Taking a leaf out of angular's book on how they deal with

    <form name="my_form"></form>
    

    using $parse and registering controller on $parent scope. This technique doesn't work on isolated $scope directives.

    angular.module('myModule').directive('myDirective', function($parse) {
        var directive = {
            link: link,
            controller: controller,
            scope: true
        };
    
        return directive;
    
        function link() {
            //link fn code
        }
    
        function controller($scope, $attrs) {
            $parse($attrs.name).assign($scope.$parent, this);
    
            this.updateMap = function() {
                //some code
            };
        }
    })
    

    Access it inside controller using $scope.foo

    angular.module('myModule').controller('MyController', function($scope) {
        $scope.someFn = function() {
            $scope.foo.updateMap();
        };
    });
    
    0 讨论(0)
  • 2020-11-22 15:32

    Just use scope.$parent to associate function called to directive function

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

    in HTML

    <div ng-controller="MyCtrl">
        <mydirective></mydirective>
        <button ng-click="myfunction(parameter)">call()</button>
    </div>
    
    0 讨论(0)
提交回复
热议问题