【问题标题】:Call a method of a controller from another controller using 'scope' in AngularJS使用AngularJS中的“范围”从另一个控制器调用控制器的方法
【发布时间】:2013-10-28 09:35:11
【问题描述】:

我正在尝试使用scope 变量在第一个控制器中调用第二个控制器的方法。这是我的第一个控制器中的一个方法:

$scope.initRestId = function(){
        var catapp = document.getElementById('SecondApp');
        var catscope = angular.element(catapp).scope();
        catscope.rest_id = $scope.user.username;
        catscope.getMainCategories();
    }; 

我可以设置rest_id 的值,但由于某种原因我不能调用getMainCategories。控制台显示此错误:

TypeError: Object # has no method 'getMainCategories'

有没有办法调用上面的方法?

编辑:

我使用下面的方法同时加载了两个应用;

angular.bootstrap(document.getElementById('firstAppID'), ['firstApp']);
angular.bootstrap(document.getElementById('secondAppID'), ['secondApp']);

我绝对可以在这里使用服务,但我想知道是否有其他选择可以做到这一点!

【问题讨论】:

    标签: angularjs angularjs-directive angularjs-scope


    【解决方案1】:

    每个控制器都有自己的范围,因此会导致您的问题。

    拥有两个想要访问相同数据的控制器是您需要服务的典型标志。 Angular 团队推荐将视图和服务粘合在一起的瘦控制器。特别是“服务应该在控制器之间保持共享状态”。

    令人高兴的是,有一段 15 分钟的精彩视频准确描述了这一点(通过服务进行控制器通信):video

    Angular 的原作者之一 Misko Hevery 在他题为 Angular Best Practices 的演讲中讨论了这个建议(在这种情况下使用服务)(这个话题跳到 28:08,尽管我非常强烈建议观看整个说话)。

    您可以使用事件,但它们只是为想要解耦的两方之间的通信而设计的。在上面的视频中,Misko 指出了它们如何使您的应用程序更加脆弱。 “大多数情况下,注入服务和进行直接通信是首选且更健壮的”。 (从 53:37 开始查看上面的链接,听听他谈论这个)

    【讨论】:

    • 谢谢,我已经编辑了我的问题,我很想知道我的问题是否可以在不将当前方法作为服务的情况下解决?
    • 你可以,我更新了我的答案,其中一位作者的角度进行了一些精彩的讨论,如果你想保持“角度方式”,我发现这些讨论非常有帮助。但是请务必查看事件 - 他们也很高兴知道。
    【解决方案2】:

    在两个控制器之间进行通信的最佳方法是使用事件。

    Scope Documentation

    在此查看$on$broadcast$emit

    在一般用例中,angular.element(catapp).scope() 的使用是为在角度控制器之外使用而设计的,例如在 jquery 事件中。

    理想情况下,您可以在控制器 1 中编写一个事件:

    $scope.$on("myEvent", function (event, args) {
       $scope.rest_id = args.username;
       $scope.getMainCategories();
    });
    

    而在第二个控制器中,您只需这样做

    $scope.initRestId = function(){
       $scope.$broadcast("myEvent", {username: $scope.user.username });
    };
    

    编辑:意识到这是两个模块之间的通信

    您能否尝试将 firstApp 模块作为对声明 angular.modulesecondApp 的依赖项包含在内。这样您就可以与其他应用通信。

    【讨论】:

    • 其实你应该使用$rootScope.$emit或者$scope.$root.$emit。 $on 和 $broadcast 的同义词
    • @ArifNadeem 我很快就会给你发一个可行的解决方案。
    • 这里有一个 $broadcast 例子。 http://jsfiddle.net/XjAfr/
    • @ArifNadeem 如果您不想过度设计其小型应用程序,我建议您坚持使用事件。如果您看到太多的事件正在蔓延以促进控制器之间的通信,请停止您正在做的一切并编写服务。 :)
    • 这里有一个小提琴,它可以让你使用 2 个模块的原始方法起作用:2 module fiddle :)
    【解决方案3】:

    这里是Fiddle中很好的演示,如何通过$scope.$on在指令和其他控制器中使用共享服务

    HTML

    <div ng-controller="ControllerZero">
        <input ng-model="message" >
        <button ng-click="handleClick(message);">BROADCAST</button>
    </div>
    
    <div ng-controller="ControllerOne">
        <input ng-model="message" >
    </div>
    
    <div ng-controller="ControllerTwo">
        <input ng-model="message" >
    </div>
    
    <my-component ng-model="message"></my-component>
    

    JS

    var myModule = angular.module('myModule', []);
    
    myModule.factory('mySharedService', function($rootScope) {
        var sharedService = {};
    
        sharedService.message = '';
    
        sharedService.prepForBroadcast = function(msg) {
            this.message = msg;
            this.broadcastItem();
        };
    
        sharedService.broadcastItem = function() {
            $rootScope.$broadcast('handleBroadcast');
        };
    
        return sharedService;
    });
    

    通过同样的方式我们可以在指令中使用共享服务。我们可以将控制器部分实现为指令并使用$scope.$on

    myModule.directive('myComponent', function(mySharedService) {
        return {
            restrict: 'E',
            controller: function($scope, $attrs, mySharedService) {
                $scope.$on('handleBroadcast', function() {
                    $scope.message = 'Directive: ' + mySharedService.message;
                });
            },
            replace: true,
            template: '<input>'
        };
    });
    

    这里是我们的三个控制器,其中ControllerZero 用作触发prepForBroadcast

    function ControllerZero($scope, sharedService) {
        $scope.handleClick = function(msg) {
            sharedService.prepForBroadcast(msg);
        };
    
        $scope.$on('handleBroadcast', function() {
            $scope.message = sharedService.message;
        });
    }
    
    function ControllerOne($scope, sharedService) {
        $scope.$on('handleBroadcast', function() {
            $scope.message = 'ONE: ' + sharedService.message;
        });
    }
    
    function ControllerTwo($scope, sharedService) {
        $scope.$on('handleBroadcast', function() {
            $scope.message = 'TWO: ' + sharedService.message;
        });
    }
    

    ControllerOneControllerTwo 监听 message 通过使用 $scope.$on 处理程序进行更改。

    【讨论】:

    • 如何使用简单的服务在控制器之间进行通信的一个很好的简单示例!
    • 太棒了 .. 即使我从控制器 1 设置了服务中的值,我也需要确保控制器 2 知道这一点并相应地更新。你的回答很有魅力。
    • Dmn,我已经使用 Angular 多年了,这是我遇到的最漂亮的实现。 mySharedService 将被重命名,它将在我所有项目中使用的收藏中占据一席之地。稍加修饰(即,我认为消息需要一个信封),它可以处理 98% 的通信需求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    相关资源
    最近更新 更多