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

时间:2013-05-23 08:45:00

标签: angularjs

如何从网页的任何位置(控制器组件之外)调用控制器下定义的函数?

当我按下“获取”按钮时它完美运行。但我需要从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>

我的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){ }
      });
    };
   }

10 个答案:

答案 0 :(得分:321)

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

angular.element(document.getElementById('yourControllerElementID')).scope().get();

其中get()是您控制器的功能。

您可以切换

document.getElementById('yourControllerElementID')` 

$('#yourControllerElementID')

如果您使用的是jQuery。

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

angular.element(document.getElementById('yourControllerElementID')).scope().$apply();

应用更改。

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

<强>更新

使用最新版本的angular,您应该使用

angular.element(document.getElementById('yourControllerElementID')).injector().‌​get('$rootScope')

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

答案 1 :(得分:36)

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

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

<强> 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>

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

Demo

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

答案 2 :(得分: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>

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

答案 3 :(得分:9)

解决方案 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;
})

从自定义代码调用:

scopeHolder.bar()

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

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

从自定义代码调用:

scopeHolder()

答案 4 :(得分:7)

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

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

function ControllerZero($scope, mySharedService) {
    $scope.thing = mySharedService.thing;

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

答案 5 :(得分:5)

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

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

如果最终确定没有示波器的菜单,另外要考虑的是,如果您有多个路径,那么所有控制器都必须拥有自己的upate和get函数。 (假设您有多个控制器)

答案 6 :(得分:4)

我习惯使用$ http,当想要从资源中获取一些信息时,我会执行以下操作:

angular.module('services.value', [])

.service('Value', function($http, $q) {

var URL = "http://localhost:8080/myWeb/rest/";

var valid = false;

return {
    isValid: valid,
    getIsValid: function(callback){
        return $http.get(URL + email+'/'+password, {cache: false})
                    .success(function(data){
            if(data === 'true'){ valid = true; }
        }).then(callback);
    }}
    });

控制器中的代码:

angular.module('controllers.value', ['services.value'])

.controller('ValueController', function($scope, Value) {
    $scope.obtainValue = function(){
        Value.getIsValid(function(){$scope.printValue();});
    }

    $scope.printValue = function(){
        console.log("Do it, and value is " Value.isValid);
    }
}

我向服务发送了必须在控制器中调用的函数

答案 7 :(得分:3)

我有多条路线和多个控制器,所以我无法获得接受的工作答案。我发现在窗口中添加函数有效:

EditText

然后在控制器外面,可以这样做:

fooModule.controller("fooViewModel", function ($scope, fooService, $http, $q, $routeParams, $window, $location, viewModelHelper, $interval) {
    $scope.initFoo = function () {
        // do angular stuff
    }
    var initialize = function () {
        $scope.initFoo();
    }

    initialize();

    window.fooreinit = initialize;

}

答案 8 :(得分:0)

我是一个Ionic框架用户,我发现它将始终如一地提供当前控制器的$ scope:

... 2444 18472 29912 25180 6612 29440 13220 4684 14004 12388 16424 26320 25948 28076 30904 6396 1160 4228 ...

我怀疑通过查找将定位仅在给定控制器实例期间可用的特定DOM元素的查询,可以修改此问题以适应大多数情况,无论框架(或不是框架)。

答案 9 :(得分:0)

从控制器外部调用Angular Scope功能。

// Simply Use "Body" tag, Don't try/confuse using id/class.

var scope = angular.element('body').scope();             
scope.$apply(function () {scope.YourAngularJSFunction()});