控制器间通信,角度方式 [英] Inter-Controller communication, the angular way

查看:23
本文介绍了控制器间通信,角度方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出在控制器/指令之间共享属性或状态的首选"或角度方式".有几种方法可以实现这一点,但我想保持最佳实践.下面是一些关于如何实现这一点的普通示例:

<小时>

1.使用 $scope.$watch

//父控制器/作用域angular.module('myModule').controller('parentController', ['$scope', function($scope) {$scope.state = {myProperty: 'someState';//某些 DOM 元素要更改的默认值};}]);//子控制器/范围.angular.module('myModule').controller('childController', ['$scope', function($scope) {$scope.$watch('state.myProperty', function (newVal) {//在这里对状态改变做一些动作});}]);

编辑:根据下面的答案,这是不好的做法,应该避免.它是不可测试的,并且存在不需要的 DOM 依赖.

<小时>

2.使用 $broadcast

//父控制器angular.module('myModule').controller('parentController', ['$scope', function($scope) {var myProperty = 'someState';$scope.setState = 函数(状态){myProperty = 状态;//由一些其他控制器操作或 DOM 交互设置.$scope.$broadcast('stateChanged', state);//将更改传达给子控制器}}]);//子控制器.angular.module('myModule').controller('childController', ['$scope', function($scope) {$scope.$on('stateChanged', function (evt, state) {//在这里做一些动作}}]);

编辑:同样不好的做法,因为您需要知道控制器在 DOM 中的位置,以确定要使用 $broadcast(在 DOM 上)或 $emit(在 DOM 上)的天气.

<小时>

3.使用服务

angular.module('myModule').factory('stateContainer', [function () {变量状态 = {我的属性:'默认状态'},听众 = [];返回 {设置状态:函数(新状态){state.myProperty = newState;angular.forEach(监听器,函数(监听器){听众(新状态);});},添加侦听器:函数(侦听器){listeners.push(listener);}}}]);//父控制器angular.module('myModule').controller('parentController', ['$scope', 'stateContainer', function($scope, stateContainer) {$scope.setState = 函数(状态){stateContainer.setState(state);};}]);//子控制器.angular.module('myModule').controller('childController', ['$scope', 'stateContainer', function($scope, stateContainer) {stateContainer.addListener(function (newState) {//在这里做一些动作});}]);

我可能在这里遗漏了一些方法,但您明白了.我正在努力寻找最佳方法.虽然冗长,但我个人倾向于此处列表中的 #3.但我来自 Java 和 jQuery 背景,其中监听器被广泛使用.

编辑:下面的回答很有见地.一种使用 require 指令配置在父/子指令之间共享状态的讨论.另一个是直接向范围共享服务或服务属性.我相信,根据需要,它们在 Angular 中的最佳实践是什么或不是什么方面都是正确的.

解决方案

如果正确完成,任何这些都可以工作,但服务的变体是 AFAIK 的首选方式.

问题是,在服务案例中您甚至需要监听器吗?Angular 本身会更新任何视图(这是控制器的目的),那么为什么需要监听器或观察器呢?改变视图的值本身就足够了.

app.factory('stateService',function() {返回 {我的状态:富"}}).controller('one',function($scope,stateService) {$scope.changeState = function() {stateService.myState = $scope.state;};}).controller('two',function($scope,stateService){$scope.svc = stateService;})

然后您可以在您的视图中执行以下操作(不完整):

<input name="state" ng-model="state"></input><button type="submit" ng-click="changeState()">提交</button>

<div ng-controller="two">{{svc.myState}}</div>

事实是,拥有一个按钮和一个功能,你甚至不需要走那么远.如果你只是将 ng-model 绑定在一起,它会起作用:

<input name="state" ng-model="svc.myState"></input>

<div ng-controller="two">{{svc.myState}}</div>

试试下面的jsfiddle http://jsfiddle.net/cwt9L6vn/1/>

I'm trying to figure out the "preferred" or "angular-way" of sharing properties or state between controllers/directives. There are several methods to implement this, but I want to keep with best-practice. Below are some banal examples of how this can be implemented:


1. Using $scope.$watch

// The parent controller/scope
angular.module('myModule').controller('parentController', ['$scope', function($scope) {
    $scope.state = {
        myProperty: 'someState'; // Default value to be changed by some DOM element
    };
}]);

// The child controller/scope.
angular.module('myModule').controller('childController', ['$scope', function($scope) {
    $scope.$watch('state.myProperty', function (newVal) {
        // Do some action here on state change
    });
}]);

Edit: Based on answers below, this is bad practice and should be avoided. It is untestable and places an unwanted DOM dependancy.


2. Using $broadcast

// The parent controller
angular.module('myModule').controller('parentController', ['$scope', function($scope) {
    var myProperty = 'someState';
    $scope.setState = function (state) {
        myProperty = state; // Set by some other controller action or DOM interaction.
        $scope.$broadcast('stateChanged', state); // Communicate changes to child controller
    }
}]);

// The child controller.
angular.module('myModule').controller('childController', ['$scope', function($scope) {
    $scope.$on('stateChanged', function (evt, state) {
        // Do some action here
    }
}]);

Edit: Equally bad practice as you need to know the placement of the controllers in the DOM in order to determine weather to use $broadcast (down the DOM) or $emit (up the DOM).


3. Using service

angular.module('myModule').factory('stateContainer', [function () {
    var state = {
            myProperty: 'defaultState'
        },
        listeners = [];

    return {
        setState: function (newState) {
            state.myProperty = newState;
            angular.forEach(listeners, function (listener) {
                listener(newState);
            });
        },
        addListener: function (listener) {
            listeners.push(listener);
        }
    }
}]);

// The parent controller
angular.module('myModule').controller('parentController', ['$scope', 'stateContainer', function($scope, stateContainer) {
    $scope.setState = function (state) {
        stateContainer.setState(state);
    };
}]);

// The child controller.
angular.module('myModule').controller('childController', ['$scope', 'stateContainer', function($scope, stateContainer) {
    stateContainer.addListener(function (newState) {
        // Do some action here
    });
}]);

There are probably some approaches I've missed here, but you get the idea. I'm trying to find the best approach. Although verbose, I personally lean towards #3 in the list here. But I come from a Java and jQuery background where listeners are widely used.

Edit: Answers below are insightful. One talks of sharing state between parent/child directives using the require directive configuration. The other talks of sharing service or service properties directly to the scope. I believe that depending on the need, they are both right in what is or is not best practice in Angular.

解决方案

Any of these will work if done correctly, but a variant on service is the preferred way AFAIK.

The question is, do you even need a listener in the service case? Angular itself will update any views (which is the purpose of the controller), so why do you need a listener or watch? It is sufficient to change the value itself for the view to be changed.

app.factory('stateService',function() {
  return {
     myState: "foo"
  }
})
.controller('one',function($scope,stateService) {
    $scope.changeState = function() {
      stateService.myState = $scope.state;
    };
})
.controller('two',function($scope,stateService) {
    $scope.svc = stateService;
})

You can then do the following in your view (incomplete):

<div ng-controller="one">
  <input name="state" ng-model="state"></input>
  <button type="submit" ng-click="changeState()">Submit</button>
</div>
<div ng-controller="two">{{svc.myState}}</div>

Truth is, you don't even need to go that far with having a button and a function. If you just tie the ng-model together it will work:

<div ng-controller="one">
  <input name="state" ng-model="svc.myState"></input>
</div>
<div ng-controller="two">{{svc.myState}}</div>

Try the following jsfiddle http://jsfiddle.net/cwt9L6vn/1/

这篇关于控制器间通信,角度方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆