AngularJS.如何从控制器组件外部调用控制器功能

Pav*_*rov 186 angularjs

如何从网页的任何地方(控制器组件之外)调用控制器下定义的功能?

当我按下"get"按钮时它完美地工作.但我需要从div控制器外部调用它.逻辑是:默认情况下我的div是隐藏的.在导航菜单的某处我按下一个按钮,它应该显示()我的div并执行"get"功能.我怎么能做到这一点?

我的网页是:

<div ng-controller="MyController">
  <input type="text" ng-model="data.firstname" required>
  <input type='text' ng-model="data.lastname" required>

  <form ng-submit="update()"><input type="submit" value="update"></form>
  <form ng-submit="get()"><input type="submit" value="get"></form>
</div>
Run Code Online (Sandbox Code Playgroud)

我的js:

   function MyController($scope) {
      // default data and structure
      $scope.data = {
        "firstname" : "Nicolas",
        "lastname" : "Cage"
      };

      $scope.get = function() {
        $.ajax({
           url: "/php/get_data.php?",
           type: "POST",
           timeout: 10000, // 10 seconds for getting result, otherwise error.
           error:function() { alert("Temporary error. Please try again...");},
           complete: function(){ $.unblockUI();},
           beforeSend: function(){ $.blockUI()},
           success: function(data){
            json_answer = eval('(' + data + ')');
            if (json_answer){
                $scope.$apply(function () {
                  $scope.data = json_answer;
            });
            }
        }
    });
  };

  $scope.update = function() {
    $.ajax({
        url: "/php/update_data.php?",
        type: "POST",
        data: $scope.data,
        timeout: 10000, // 10 seconds for getting result, otherwise error.
        error:function() { alert("Temporary error. Please try again...");},
        complete: function(){ $.unblockUI();},
        beforeSend: function(){ $.blockUI()},
        success: function(data){ }
      });
    };
   }
Run Code Online (Sandbox Code Playgroud)

Dmi*_*ina 324

这是一种从外部调用控制器函数的方法:

angular.element(document.getElementById('yourControllerElementID')).scope().get();
Run Code Online (Sandbox Code Playgroud)

哪里get()是你的控制器的功能.

你可以切换

document.getElementById('yourControllerElementID')` 
Run Code Online (Sandbox Code Playgroud)

$('#yourControllerElementID')
Run Code Online (Sandbox Code Playgroud)

如果你正在使用jQuery.

此外,如果您的功能意味着更改View上的任何内容,则应致电

angular.element(document.getElementById('yourControllerElementID')).scope().$apply();
Run Code Online (Sandbox Code Playgroud)

应用更改.

还有一件事,你应该注意的是,在加载页面之后初始化作用域,因此在加载页面之后应该始终在作用域之外调用作用域.否则你根本不会进入范围.

更新:

使用最新版本的角度,您应该使用

angular.element(document.getElementById('yourControllerElementID')).injector().??get('$rootScope')
Run Code Online (Sandbox Code Playgroud)

事实上,这实际上是一种不好的做法,但有时你只需要快速而肮脏的事情.

  • 这似乎是代码味道,因为Angular的哲学不是将DOM代码与Angular代码混合...... (30认同)
  • 因此,如果您不应该将DOM代码与Angular代码混合使用,如果您希望某些JQuery动画能够响应Angular控制器中的变量而触发 - 您究竟是如何做到的?从控制器做起来是微不足道的,但我不知道如何干净利落地做到这一点 (8认同)
  • 我无法让'$ apply`部分为我工作,直到我将代码包装到函数中,例如`..scope.$ apply(function(){scope.get()});` (3认同)
  • 我实际上可以使用```angular.element(document.getElementById('yourControllerElementID'))来访问控制器.scope().controller;```例如.如果使用:```angular.element(document.getElementById('controller')).scope().get()```抛出和未定义的错误,但如果我使用```angular.element(document.getElementById( 'controller')).scope().controller.get()```它的工作原理. (2认同)
  • 是否有可能,此解决方案不再适用于Angular 1.4.9?我无法在`angular.element(...)`中访问`scope()`,因为它返回undefined,而angular元素/对象的vardump表示函数`scope`位于`__proto__`对象中. (2认同)

Rog*_*mos 37

我在互联网上找到了一个例子.

有些人写了这段代码,工作得很好

HTML

<div ng-cloak ng-app="ManagerApp">
    <div id="MainWrap" class="container" ng-controller="ManagerCtrl">
       <span class="label label-info label-ext">Exposing Controller Function outside the module via onClick function call</span>
       <button onClick='ajaxResultPost("Update:Name:With:JOHN","accept",true);'>click me</button>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.data"></span>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.type"></span>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.res"></span>
       <br/>
       <input type="text" ng-model="sampletext" size="60">
       <br/>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

JAVASCRIPT

var angularApp = angular.module('ManagerApp', []);
angularApp.controller('ManagerCtrl', ['$scope', function ($scope) {

$scope.customParams = {};

$scope.updateCustomRequest = function (data, type, res) {
    $scope.customParams.data = data;
    $scope.customParams.type = type;
    $scope.customParams.res = res;
    $scope.sampletext = "input text: " + data;
};



}]);

function ajaxResultPost(data, type, res) {
    var scope = angular.element(document.getElementById("MainWrap")).scope();
    scope.$apply(function () {
    scope.updateCustomRequest(data, type, res);
    });
}
Run Code Online (Sandbox Code Playgroud)

演示

*我做了一些修改,见原文:font JSfiddle

  • 谢谢罗杰,非常有用! (2认同)

use*_*883 12

解决方案 angular.element(document.getElementById('ID')).scope().get()在角度1.5.2中停止了工作.Sombody在评论中提到这在1.4.9中也不起作用.我通过将范围存储在全局变量中来修复它:

var scopeHolder;
angular.module('fooApp').controller('appCtrl', function ($scope) {
    $scope = function bar(){
        console.log("foo");        
    };
    scopeHolder = $scope;
})
Run Code Online (Sandbox Code Playgroud)

从自定义代码调用:

scopeHolder.bar()
Run Code Online (Sandbox Code Playgroud)

如果要将范围限制为仅此方法.尽量减少整个范围的暴露.使用以下技术.

var scopeHolder;
angular.module('fooApp').controller('appCtrl', function ($scope) {
    $scope.bar = function(){
        console.log("foo");        
    };
    scopeHolder = $scope.bar;
})
Run Code Online (Sandbox Code Playgroud)

从自定义代码调用:

scopeHolder()
Run Code Online (Sandbox Code Playgroud)


Raz*_*aul 11

德米特里的回答很好.我只是使用相同的技术做了一个简单的例子.

jsfiddle:http://jsfiddle.net/o895a8n8/5/

<button onclick="call()">Call Controller's method from outside</button>
<div  id="container" ng-app="" ng-controller="testController">
</div>
Run Code Online (Sandbox Code Playgroud)

.

function call() {
    var scope = angular.element(document.getElementById('container')).scope();
      scope.$apply(function(){
        scope.msg = scope.msg + ' I am the newly addded message from the outside of the controller.';
    })
    alert(scope.returnHello());
}

function testController($scope) {
    $scope.msg = "Hello from a controller method.";
    $scope.returnHello = function() {
        return $scope.msg ; 
    }
}
Run Code Online (Sandbox Code Playgroud)


get*_*bro 7

我宁愿将工厂作为依赖项包含在控制器上,而不是使用自己的代码注入它们:http://jsfiddle.net/XqDxG/550/

myModule.factory('mySharedService', function($rootScope) {
    return sharedService = {thing:"value"};
});

function ControllerZero($scope, mySharedService) {
    $scope.thing = mySharedService.thing;
Run Code Online (Sandbox Code Playgroud)

ControllerZero.$ inject = ['$ scope','mySharedService'];


Ant*_*ton 5

如果没有任何相关范围的菜单是正确的方法,可能值得考虑.它不是真正的角度方式.

但是,如果它是您需要的方式,那么您可以通过将函数添加到$ rootScope然后在这些函数中使用$ broadcast来发送事件来实现.然后你的控制器使用$ on来监听这些事件.

如果你的菜单没有范围,最后要考虑的另一件事是,如果你有多条路线,那么你的所有控制器都必须有自己的upate和get函数.(假设您有多个控制器)