How to share data between controllers in angular app in the right way

前端 未结 3 553
悲哀的现实
悲哀的现实 2021-01-14 10:26

Well, seems that this is not the first question about this subject, but...

I know that we can use service or events for this, but there are many posts on the interne

相关标签:
3条回答
  • 2021-01-14 10:35

    Check out my post here about using services to share data between controllers: http://erikaugust.com/thoughts/angularjs-use-the-service-not-the-controller/?ws=so

    There's a link to a JSFiddle example at the bottom of the blog post that will help.

    0 讨论(0)
  • 2021-01-14 10:37

    You can bind the context of the controller directly to the service. This gives you several benefits: (1) you don't have to use $scope a lot; (2) you don't have to define properties in your directive's isolate scopes; (3) you don't have to touch $rootScope; (4) you don't have to use $watch or $observe, since everything that needs to be bound to something will be bound to the internal API of your global service.

    This pattern is useful for applications that need to share and be aware of lots of data between a large number of components. I used this pattern in a video player where many distantly-related parts of the application had to share information and have access to each other's state: for instance, how many video players were in the view, the current time, duration and source of each player, etc.

    This pattern isn't particularly suited for building truly reusable components. If you choose to use a service like this, the directive is hardcoded to rely on a certain service. However, you can define all the properties your application's components need in a single value component which is handy for defining your internal API.

    With dirty checking, I'm not sure if sharing a potentially large object is a performance burden.

    directive

    function() {
        return {
            //if you want the service to hold all the data the directive needs
            //you don't need to define any properties here
            scope: {},
            controller: "SomeCtrl"
        };
    }
    

    directive's controller

    angular
        .module("app")
        .controller("SomeCtrl", ["globalService", function(globalService) {
            var vm = this;
            vm.globalService = globalService;
        }]);
    

    html

    <div>{{vm.globalService.someProperty}}</div>
    

    in some deeply nested template url

    <!-- another tradeoff is the long naming that can result -->
    
    <div 
        ng-click="panel.state = !panel.state;"
        ng-repeat="panel in vm.globalService.dashboard.sidebar.panelConfig">{{panel.display}}</div>
    

    constants

    angular
        .module("app")
        .value("internalAPI", {
            someInitializedThing: true,
            someConfig: [
                { state: true, display: "foobar" },
                { state: false, display: "starts off false" }
            ],
            dashboard: {
                sidebar: {
                    panelConfig: [
                        { display: "one panel", state: true },
                        { display: "special panel", state: false }
                    ]
                }
            }  
        });
    

    let your service register the API you've defined

    angular
        .module("app")
        .service("globalService", ["internalAPI", function(API) {
            var tmp = {};
            for (var p in API)
                tmp[p] = API[p];
            return tmp;
        }])
    
        //now someplace else, globalService.someNavBar = true
    
    0 讨论(0)
  • 2021-01-14 10:44

    One way is using scope inheritance:

    angular.module('app', [])
    .run(['$rootScope', function($rootScope){
      $rootScope.sharedObj = {search:''};
    }])
    .controller('navCtr',['$scope',function($scope){
    }])
    .controller('routeCtr',['$scope',function($scope){
      $scope.$watch("sharedObj.search",function(d){
        $scope.data = d ? 'Searched data is ' + d : '';
      });
    }]);
    .main div{
      display:inline-block;
      border:1px solid black;
      height:100px;
      vertical-align: top;
    }
    
    .navigation{
      width: 20%
    }
    .navigation input{
      max-width: 70%;
    }
    
    .page {
      width: 75%
    }
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="app" class="main">
      <div ng-controller="navCtr" class="navigation">
        search: <br/>
        <input ng-model="sharedObj.search"/>
      </div>
      <div ng-controller="routeCtr" class="page">
        {{data}}
      </div>
    </div>

    the second way would be a shared service:

    angular.module('app', [])
    .factory('srcObject',[function(){
      return {
        value: ''
      }
    }])
    .controller('navCtr',['$scope', 'srcObject', function($scope, srcObject){
      $scope.search = srcObject;
    }])
    .controller('routeCtr',['$scope', 'srcObject', function($scope, srcObject){
      $scope.$watch(function(){return srcObject.value},function(d){
        $scope.data = d ? 'Searched data is ' + d : '';
      });
    }]);
    .main div{
      display:inline-block;
      border:1px solid black;
      height:100px;
      vertical-align: top;
    }
    
    .navigation{
      width: 20%
    }
    .navigation input{
      max-width: 70%;
    }
    
    .page {
      width: 75%
    }
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="app" class="main">
      <div ng-controller="navCtr" class="navigation">
        search: <br/>
        <input ng-model="search.value"/>
      </div>
      <div ng-controller="routeCtr" class="page">
        {{data}}
      </div>
    </div>

    0 讨论(0)
提交回复
热议问题