AngularJS - 从Controller调用特定的指令函数/方法

时间:2016-11-29 05:59:02

标签: javascript angularjs angularjs-directive

指令

 myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window, pictureboxConstants) {


    var linker = function (scope, element, attrs) {


    vlcPlayerCustomTemplate = 'some html goes here';


                scope.getVLC = function (name) {
                    if ($window.document[name]) {
                        return $window.document[name];
                    }
                    if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
                        if ($window.document.embeds && $window.document.embeds[name])
                            return $window.document.embeds[name];
                    } else {
                        return $window.document.getElementById(name);
                    }
                }

                scope.doPlayPause = function (vlcPlayer, event) {
                    var vlc = scope.getVLC(vlcPlayer);
                    if (vlc) {

                        if (vlc.playlist.isPlaying) {
                            vlc.playlist.pause();
                            angular.element(event.target).children().removeClass('fa fa-pause font-12');
                            angular.element(event.target).children().addClass('fa fa-play font-12');

                        } else {
                            if (vlc.audio.mute == true) {
                                //do something
                            }
                            vlc.playlist.play();
                        }
                    }
                }

            angular.element(document.querySelector("#controls" + index)).append(element.html(vlcPlayerCustomTemplate));
            $compile(element.contents())(scope);
    };
    return {
        restrict: "E",
        link: linker
    };
});

控制器

myModule.controller('myModuleCtrl', function ($scope, $http, $controller, $compile) {

$compile("<vlc-controls></vlc-controls>")($rootScope);

});

在不使用directive html元素或任何doPlayPause操作的情况下,仅从controller调用特定vlcPlayerCustomTemplate函数/方法DOM的最佳方法是什么?< / p>

4 个答案:

答案 0 :(得分:1)

您应该使用$broadcast$on来处理从控制器到指令的通信。

对我而言,这是一种代码味道。如果在父范围和指令范围之间共享某些内容,则应通过绑定来完成。如果你必须使用这样的pub-sub模式,你应该重新考虑如何使用你的指令IMO。

你的指令应该能够做任何需要的事情,而不是直接从父控制器调用。如果父控制器需要它,它应该使用属性或非隔离范围绑定。

答案 1 :(得分:0)

一种方法是$broadcastcontrollerdirective的事件并听取指令。

您甚至可以通过它以对象的形式发送参数。

$rootScope.$broadcast('PlayPause',{});将在控制器中

指令,

scope.$on('PlayPause',function(event, data){
      scope.doPlayPause(data.vlcPlayer, data.event)
});

<强>控制器:

myApp.controller('MyCtrl', function($rootScope){
  var that = this;

  this.select = function(){
      $rootScope.$broadcast('PlayPause',{vlcPlayer: 'vlcPlayer',event: 'event'});
  }
})

<强>指令:

myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window, pictureboxConstants) {


    var linker = function (scope, element, attrs) {


                scope.getVLC = function (name) {
                    if ($window.document[name]) {
                        return $window.document[name];
                    }
                    if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
                        if ($window.document.embeds && $window.document.embeds[name])
                            return $window.document.embeds[name];
                    } else {
                        return $window.document.getElementById(name);
                    }
                }

                scope.doPlayPause = function (vlcPlayer, event) {
                    var vlc = scope.getVLC(vlcPlayer);
                    if (vlc) {

                        if (vlc.playlist.isPlaying) {
                            vlc.playlist.pause();
                            angular.element(event.target).children().removeClass('fa fa-pause font-12');
                            angular.element(event.target).children().addClass('fa fa-play font-12');

                        } else {
                            if (vlc.audio.mute == true) {
                                //do something
                            }
                            vlc.playlist.play();
                        }
                    }
                }

                 scope.$on('PlayPause',function(event, data){
                    scope.doPlayPause(data.vlcPlayer, data.event)
                });
    };
    return {
myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window, pictureboxConstants) {


    var linker = function (scope, element, attrs) {


                scope.getVLC = function (name) {
                    if ($window.document[name]) {
                        return $window.document[name];
                    }
                    if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
                        if ($window.document.embeds && $window.document.embeds[name])
                            return $window.document.embeds[name];
                    } else {
                        return $window.document.getElementById(name);
                    }
                }

                scope.doPlayPause = function (vlcPlayer, event) {
                    var vlc = scope.getVLC(vlcPlayer);
                    if (vlc) {

                        if (vlc.playlist.isPlaying) {
                            vlc.playlist.pause();
                            angular.element(event.target).children().removeClass('fa fa-pause font-12');
                            angular.element(event.target).children().addClass('fa fa-play font-12');

                        } else {
                            if (vlc.audio.mute == true) {
                                //do something
                            }
                            vlc.playlist.play();
                        }
                    }
                }

                 scope.$on('PlayPause',function(event, data){
                    scope.doPlayPause(data.vlcPlayer, data.event)
                });
    };
    return {
        restrict: "E",
        link: linker
    };
});      

另一种方法是使用工厂并在controllerdirective之间共享方法,

Check this so post for more details

答案 2 :(得分:0)

有很多方法可以做到这一点,其中一种是通过广播一个事件并在指令中听取它

但是,我不知道整个上下文以及您想要实现的目标,但看起来设计中存在一个小问题。我要问的问题是“你为什么要在父控制器的指令中调用一个方法?”理想情况下,当你使用指令时,它的功能是自包含的,如果你需要与外部世界交互,那么你要么通过变量绑定,要么就像我已经提到的那样,事件。

我确信有一种方法可以完全按照你的意愿行事,但鉴于帖子中的信息,没有必要。

答案 3 :(得分:0)

您的目标是在没有任何directive操作的情况下调用controller中的DOM方法,您可以在isolated scope的帮助下实现相同的操作,如下所示。

您的isolated scope可以有directive,如下所示。

scope: {
           /* This is the reference object passed from the controller */
           controllerRef: '='
       }

然后你可以从controller

传递相同内容
$scope.vlcControls = {};

$compile('<vlc-controls controller-ref="vlcControls"></vlc-controls>')($scope);

然后,您可以在指令

中将方法分配给此对象
      scope.controllerRef = scope.controllerRef || {};

      angular.extend(scope.controllerRef, {
         doPlayPause: scope.doPlayPause,
         // This is just for an example
         callDirectiveFromController: scope.callDirectiveFromController
      });

现在你已经准备好从控制器中调用这些方法,如下所示,

$scope.vlcControls.callDirectiveFromController();

检查下面的代码并按预期执行哪个代码正常: - )

var myApp = angular.module('myApp', []);

myApp.controller('myModuleCtrl', function ($scope, $http, $controller, $compile) {
   $scope.vlcControls = {};
  
   $compile('<vlc-controls controller-ref="vlcControls"></vlc-controls>')($scope);
  
   $scope.vlcControls.callDirectiveFromController();

});

myApp.directive('vlcControls', function ($compile, $rootScope, $timeout, $window)//, pictureboxConstants) 
            {


    var linker = function (scope, element, attrs) {


                scope.getVLC = function (name) {
                    if ($window.document[name]) {
                        return $window.document[name];
                    }
                    if ($window.navigator.appName.indexOf("Microsoft Internet") == -1) {
                        if ($window.document.embeds && $window.document.embeds[name])
                            return $window.document.embeds[name];
                    } else {
                        return $window.document.getElementById(name);
                    }
                };

                scope.doPlayPause = function (vlcPlayer, event) {
                    var vlc = scope.getVLC(vlcPlayer);
                    if (vlc) {

                        if (vlc.playlist.isPlaying) {
                            vlc.playlist.pause();
                            angular.element(event.target).children().removeClass('fa fa-pause font-12');
                            angular.element(event.target).children().addClass('fa fa-play font-12');

                        } else {
                            if (vlc.audio.mute == true) {
                                //do something
                            }
                            vlc.playlist.play();
                        }
                    }
                };
      
           scope.callDirectiveFromController = function() {
              console.log('I called from the controller but executed inside the directive :-)');
           };
   
          scope.controllerRef = scope.controllerRef || {};

          angular.extend(scope.controllerRef, {
             doPlayPause: scope.doPlayPause,
             // This is just for an example
             callDirectiveFromController: scope.callDirectiveFromController
          });
    };
    return {
        restrict: "E",
        scope: {
          /* This is the reference object passed from the controller */
          controllerRef: '='
        },
        link: linker
    };
});

angular.bootstrap(document, ['myApp']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="myModuleCtrl">
</div>