控制器间通信,角度方式

Øys*_*sen 4 angularjs angularjs-scope

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


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
    });
}]);
Run Code Online (Sandbox Code Playgroud)

编辑:根据下面的答案,这是不好的做法,应该避免.它是不可测试的并且放置了不需要的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
    }
}]);
Run Code Online (Sandbox Code Playgroud)

编辑:同样糟糕的做法,因为你需要知道控制器在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
    });
}]);
Run Code Online (Sandbox Code Playgroud)

可能有一些我在这里错过的方法,但你明白了.我正在努力寻找最好的方法.虽然冗长,但我个人倾向于列表中的#3.但我来自Java和jQuery背景,其中听众被广泛使用.

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

dei*_*tch 5

如果正确完成,任何这些都将有效,但服务上的变体是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;
})
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

事实上,你甚至不需要通过按钮和功能去那么远.如果你只是将ng-model它们绑在一起它将起作用:

<div ng-controller="one">
  <input name="state" ng-model="svc.myState"></input>
</div>
<div ng-controller="two">{{svc.myState}}</div>
Run Code Online (Sandbox Code Playgroud)

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

  • 这被称为**范围出血**,这是一个非常糟糕的做法. (2认同)
  • 我认为该观点不应该知道数据的来源.在此示例中,视图知道服务.我认为控制器应该保持状态,然后视图将只使用控制器.在视图中:`{{ctrl.myState}}`(使用ControllerAs语法)在Ctrl:`ctrl.myState = myService.myState;`这样,控制器可以决定保留状态或原始引用的副本.这打开了保存/取消,验证检查,......的大门. (2认同)
  • 是的,所有评论者都是100%正确的; 将服务*直接暴露*到视图是不好的做法.这只是一个简单的例子,表明它有效,但你是对的.但是,要小心使用Oystein的例子,因为如果它只是文本,你会失去一些观看.通常,您希望视图查看对象,这就是我选择最简单路径的原因.我将在上面更新它,但请注意"我需要一个点"http://nathanleclaire.com/blog/2014/04/19/5-angularjs-antipatterns-and-pitfalls/ (2认同)