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

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

问题描述

我试图找出控制器/指令之间共享属性或状态的首选"或角度".有几种方法可以实现此目的,但我想保持最佳实践.下面是一些平庸的例子,说明了如何实现:


1.使用$ 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
    });
}]);

编辑:根据以下答案,这是一种不好的做法,应避免使用.它是不可测试的,并且具有不必要的DOM依赖性.


2.使用$ 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
    }
}]);

编辑:同样地,这是一种不好的做法,因为您需要知道控制器在DOM中的位置才能确定使用$ broadcast(在DOM下方)或$ emit(在DOM上方)的天气


3.使用服务

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

我可能在这里错过了一些方法,但是您明白了.我正在尝试找到最佳方法.尽管冗长,但我个人还是倾向于此处列表中的#3.但是我来自Java和jQuery的背景,其中侦听器被广泛使用.

编辑:以下答案很有见地.有人谈到使用require指令配置在父/子指令之间共享状态.其他谈论将服务或服务属性直接共享到作用域.我相信,根据需要,它们在Angular的最佳实践中都是正确的.

解决方案

如果正确完成,这些方法都可以使用,但是AFAIK首选使用服务变体.

问题是,在服务案例中,您是否甚至需要一个侦听器? Angular本身将更新任何视图(这是控制器的目的),那么为什么需要侦听器或监视?更改值本身就足以更改视图.

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

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

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

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

<div ng-controller="one">
  <input name="state" ng-model="svc.myState"></input>
</div>
<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天全站免登陆