ChatGPT解决这个技术问题 Extra ChatGPT

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

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

当我按下“获取”按钮时,它工作得很好。但我需要从 div 控制器外部调用它。逻辑是:默认情况下我的 div 是隐藏的。在导航菜单的某个地方,我按下一个按钮,它应该显示()我的 div 并执行“获取”功能。我怎样才能做到这一点?

我的网页是:

<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){ }
      });
    };
   }
当您说“...在导航菜单的某处按下按钮...”时,您的意思是说此导航是另一个控制器的一部分,并且您希望从另一个控制器调用 MyController 的 get()
目前导航菜单不是控制器。只是html。不确定是否可以从 html/javascript 调用控制器函数,这就是我发布这个问题的原因。但是,是的,将导航菜单作为单独的控制器是合乎逻辑的。如何从 NavigationMenu.Controller 调用 MyController.get() 函数?

D
Dmitry Mina

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

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

其中 get() 是来自您的控制器的函数。

你可以切换

document.getElementById('yourControllerElementID')` 

$('#yourControllerElementID')

如果您使用的是 jQuery。

此外,如果您的功能意味着更改视图上的任何内容,您应该调用

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

应用更改。

还有一件事,你应该注意的是,作用域是在页面加载之后初始化的,所以从作用域之外调用方法应该总是在页面加载之后完成。否则,您将根本无法到达范围。

更新:

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

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

是的,事实上,这是一种不好的做法,但有时您只需要快速而肮脏地完成事情。


这似乎是一种代码味道,因为 Angular 的理念是不将 DOM 代码与 Angular 代码混合......
因此,如果您不应该将 DOM 代码与 Angular 代码混合,如果您希望某些 JQuery 动画触发以响应您的 Angular 控制器中的变量变化 - 您究竟是如何做到的?从控制器做这将是微不足道的,但我不知道如何干净地做到这一点
我无法让 $apply 部分为我工作,直到我将代码包装到一个函数中,例如 ..scope.$apply(function() { scope.get() });
我实际上可以使用 angular.element(document.getElementById('yourControllerElementID')).scope().controller; 例如访问控制器。如果使用:angular.element(document.getElementById('controller')).scope().get() 抛出和未定义的错误,但如果我使用 angular.element(document.getElementById('controller')).scope().controller.get() 它可以工作。
有没有可能,这个解决方案不再适用于 Angular 1.4.9?我无法访问 angular.element(...) 中的 scope(),因为它返回 undefined 并且角度元素/对象的 vardump 表明函数 scope 位于 __proto__ 对象内。
M
Matt

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

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

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

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


谢谢罗杰,非常有用!
使用必须使用的遗留 jQuery 验证库。所以,要么是1:重写库,2:创建指令来包装库,3:2行代码在有效时调用角度提交......
如果我不使用 apply 那么将不会反映更新视图数据的功能?
S
Salman Lone

解决方案 angular.element(document.getElementById('ID')).scope().get() 在角度 1.5.2 中停止为我工作。有人在评论中提到这在 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()

这对我很有用(即使是在组件内部)。除了我在我的场景中无法避免的“从外部角度调用角度内容的坏习惯”之外,这样做是否有不利之处? stackoverflow.com/questions/42123120/…
感谢先生的帮助,我一直在寻找解决方案
R
Razan Paul

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

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

g
getsetbro

我宁愿将工厂作为对控制器的依赖项,也不愿用自己的代码行注入它们: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'];


唔。 @Anton 在下面评论了一个小提琴(在 13 年 5 月),两者都可以。
A
Anton

如果让您的菜单没有任何关联范围是正确的选择,则可能值得考虑。它不是真正的角度方式。

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

如果您的菜单最终没有范围,要考虑的另一件事是,如果您有多个路由,那么您的所有控制器都必须有自己的更新和获取功能。 (这是假设您有多个控制器)


你能举个简单的例子来说明如何从 ControllerTwo 调用 ControllerOne 的 .get() 函数吗?我的逻辑是每个控制器都有自己的 .get() .update() 函数。我将拥有 MainMenuController ,我需要从中执行(根据菜单项)必要控制器的 .get() 。
ps,不是我的代码,但它显示了如何让多个控制器共享功能
r
rodrimmb

我曾经使用 $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);
    }
}

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


j
jaybro

我有多个路线和多个控制器,所以我无法得到公认的答案。我发现将功能添加到窗口有效:

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;

}

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

function ElsewhereOnThePage() {
    if (typeof(fooreinit) == 'function') { fooreinit(); }
}

I
Igor F.

从控制器外部调用 Angular Scope 函数。

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

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

M
Matt Ray

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

angular.element(document.querySelector('ion-view[nav-view="active"]')).scope()

我怀疑这可以通过查找将针对仅在给定控制器实例期间可用的特定 DOM 元素的查询来修改以适应大多数场景而不管框架(或不)。