$ on和$ broadcast in angular

Ali*_*sky 276 javascript angularjs

我有一个footerController和codeScannerController具有不同的视图.

angular.module('myApp').controller('footerController', ["$scope", function($scope) {}]);

angular.module('myApp').controller('codeScannerController', ["$scope", function($scope) {
console.log("start");
$scope.startScanner = function(){...
Run Code Online (Sandbox Code Playgroud)

当我点击<li>footer.html中的一个时,我应该在codeScannerController中获取此事件.

<li class="button" ng-click="startScanner()">3</li>
Run Code Online (Sandbox Code Playgroud)

我认为它可以用$on和实现$broadcast,但我不知道怎样也无法在任何地方找到例子.

Dav*_*yon 623

如果你想$broadcast使用$rootScope:

$scope.startScanner = function() {

    $rootScope.$broadcast('scanner-started');
}
Run Code Online (Sandbox Code Playgroud)

然后接收,使用$scope您的控制器:

$scope.$on('scanner-started', function(event, args) {

    // do what you want to do
});
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以在以下情况下传递参数$broadcast:

$rootScope.$broadcast('scanner-started', { any: {} });
Run Code Online (Sandbox Code Playgroud)

接收它们:

$scope.$on('scanner-started', function(event, args) {

    var anyThing = args.any;
    // do what you want to do
});
Run Code Online (Sandbox Code Playgroud)

文档资料该内部范围的文档.

  • @Ismail` $ scope.$ apply()`只在更改角度框架之外的模型时才需要(比如在setTimeout,对话框回调或ajax回调中),换句话说`$ apply()`已经是在`.$ on()`中的所有代码完成后触发. (8认同)
  • 是否存在将这些字符串存储在某处而不是硬编码广播消息的推荐做法? (7认同)
  • 确保你是$ scope.$ apply(); 你的改变! (5认同)
  • @Ismail为什么......在哪里? (4认同)
  • 您可以根据自己的喜好命名事件. (2认同)

th3*_*guy 96

首先,简要说明$on(),$broadcast()$emit():

  • .$on(name, listener) - 按给定的方式收听特定事件 name
  • .$broadcast(name, args)- 通过$scope所有孩子广播一个活动
  • .$emit(name, args)- $scope向所有家长发布层级结构中的事件,包括$rootScope

基于以下HTML(请参阅此处的完整示例):

<div ng-controller="Controller1">
    <button ng-click="broadcast()">Broadcast 1</button>
    <button ng-click="emit()">Emit 1</button>
</div>

<div ng-controller="Controller2">
    <button ng-click="broadcast()">Broadcast 2</button>
    <button ng-click="emit()">Emit 2</button>
    <div ng-controller="Controller3">
        <button ng-click="broadcast()">Broadcast 3</button>
        <button ng-click="emit()">Emit 3</button>
        <br>
        <button ng-click="broadcastRoot()">Broadcast Root</button>
        <button ng-click="emitRoot()">Emit Root</button>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

被解雇的事件将遍历$scopes如下:

  • 广播1 - 仅由控制器1看到 $scope
  • 发射1 - $scope然后由控制器1看到$rootScope
  • 广播2 - 将由控制器2 $scope然后控制器3 看到$scope
  • 发射2 - $scope然后由控制器2看到$rootScope
  • 广播3 - 只有控制器3才能看到 $scope
  • 发射3 - 然后由控制器3 $scope,控制器2 看到$scope$rootScope
  • 广播根-将可以看到$rootScope$scope所有的控制器(1,2,则3)
  • Emit Root - 只会被看到 $rootScope

用于触发事件的JavaScript(同样,您可以在此处查看一个有效的示例):

app.controller('Controller1', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.broadcastAndEmit = function(){
        // This will be seen by Controller 1 $scope and all children $scopes 
        $scope.$broadcast('eventX', {data: '$scope.broadcast'});

        // Because this event is fired as an emit (goes up) on the $rootScope,
        // only the $rootScope will see it
        $rootScope.$emit('eventX', {data: '$rootScope.emit'});
    };
    $scope.emit = function(){
        // Controller 1 $scope, and all parent $scopes (including $rootScope) 
        // will see this event
        $scope.$emit('eventX', {data: '$scope.emit'});
    };

    $scope.$on('eventX', function(ev, args){
        console.log('eventX found on Controller1 $scope');
    });
    $rootScope.$on('eventX', function(ev, args){
        console.log('eventX found on $rootScope');
    });
}]);
Run Code Online (Sandbox Code Playgroud)


Yan*_* Li 26

你应该知道的一件事是$ prefix指的是Angular方法,$$前缀指的是你应该避免使用的angular方法.

下面是一个示例模板及其控制器,我们将探讨$ broadcast/$ on如何帮助我们实现我们想要的目标.

<div ng-controller="FirstCtrl">
    <input ng-model="name"/> 
    <button ng-click="register()">Register </button>
</div>

<div ng-controller="SecondCtrl">
    Registered Name: <input ng-model="name"/> 
</div>
Run Code Online (Sandbox Code Playgroud)

控制器是

app.controller('FirstCtrl', function($scope){
    $scope.register = function(){

    }
});

app.controller('SecondCtrl', function($scope){

});
Run Code Online (Sandbox Code Playgroud)

我的问题是,当用户点击注册时,如何将名称传递给第二个控制器?您可能会提出多种解决方案,但我们要使用的是使用$ broadcast和$ on.

$ broadcast vs $ emit

我们应该使用哪个?$ broadcast将向下传递给所有孩子的dom元素,$ emit将向所有祖先dom元素传递相反的方向.

避免在$ emit或$ broadcast之间做出决定的最佳方法是从$ rootScope进行通道并使用$ broadcast到其所有子节点.由于我们的dom元素是兄弟姐妹,这使我们的案例变得更容易.

添加$ rootScope并让$ broadcast

app.controller('FirstCtrl', function($rootScope, $scope){
    $scope.register = function(){
        $rootScope.$broadcast('BOOM!', $scope.name)
    }
});
Run Code Online (Sandbox Code Playgroud)

注意我们添加了$ rootScope,现在我们使用$ broadcast(broadcastName,arguments).对于broadcastName,我们想给它一个唯一的名称,以便我们可以在secondCtrl中捕获该名称.我选择了BOOM!纯娱乐.第二个参数'arguments'允许我们将值传递给侦听器.

接收我们的广播

在我们的第二个控制器中,我们需要设置代码来收听我们的广播

app.controller('SecondCtrl', function($scope){
  $scope.$on('BOOM!', function(events, args){
    console.log(args);
    $scope.name = args; //now we've registered!
  })
});
Run Code Online (Sandbox Code Playgroud)

这真的很简单.实例

其他方法可以达到类似的效果

尽量避免使用这套方法,因为它既不高效又不易维护,但它是解决您可能遇到的问题的简单方法.

您通常可以通过使用服务或简化控制器来执行相同的操作.我们不会详细讨论这个问题,但我认为我只是提到完整性.

最后,请记住一个真正有用的广播,再次'$ destroy'可以看到$表示它是供应商代码创建的方法或对象.无论如何,当控制器被破坏时,广播会播放$ destroy,你可能想要听听它以了解何时删除你的控制器.

  • 作为警告,请尽量不要在您的应用中使用过多的广播/发布.他们可能非常难以管理,特别是在大型应用程序中,因为追踪这些事件的根源是一项非常艰巨的任务. (2认同)