【问题标题】:Share a variable across controllers跨控制器共享变量
【发布时间】:2015-05-08 08:25:54
【问题描述】:

我有服务方法,

 var selectedType = 0;
 .........
 .........
 return {
            updateType: function (type) {
                return selectedType = type;
            },

            getType: function () {
                return selectedType;
            }
        }

我想在 2 个控制器之间共享这个 selectedType 变量。因此,从一个控制器调用 updateType 方法并打开一个新的弹出页面,我在其中调用 getType 方法。

问题是,getType 方法在弹出页面中总是返回 0,但从主页面分配的值是 2(通过调用 updateType 方法)。

主页,

angular.module('Controller1Module', [])
.controller('myController1', ['$scope', 'myService',
 function ($scope, myService) {
  myService.updateType(1);
 $scope.$watch(myService.getType , function(newValue, oldValue){                
            $scope.selectedType = myService.getType();                
        });
}

弹出控制器,

angular.module('Controller2Module', [])
.controller('myController', ['$scope', 'myService',
 function ($scope, myService) {

   $scope.$watch(myService.getType , function(newValue, oldValue){                
            $scope.selectedType = myService.getType();                
        });
}

我的服务,

angular.module('serviceModule', [])
 .service('myService', ['$rootScope',
  function($rootScope){
     var selectedType = 0;

       return {
               updateType: function (type) {
                return selectedType = type;
            },

            getType: function () {
                return selectedType;
            }
    ]);

【问题讨论】:

  • 你确定在getType之前调用了updateType吗?
  • 您的代码应该可以工作。我这样用过很多次。请将 `var selectedType = 0;` 替换为 `var selectedType;'。请将您的代码放入小提琴并发布请`
  • 如果我的控制器在不同的模块中会不会有问题?
  • @VeeraBhadra 我已经更新了我的代码,你能检查一下并提供你的输入吗?
  • @Nic 是的,Nic。请使用模块。如果你想使用不同的模块注入和使用。

标签: angularjs


【解决方案1】:

这是一个使用$scope.$watch 来查看myService.getType() 变化的示例。这个特定的实现使用了watch,因为myService.getType()返回的值是一个字符串(它是一个值),而不是一个对象(它返回一个引用)——服务的selectedType属性的任何变化都不会被自动注意到控制器中的范围,因为它们只收到了调用 getType() 时服务中的值。

(function() {
  angular.module('myApp', [])
    .controller('Controller1', ['$scope', 'myService', Controller1])
    .controller('Controller2', ['$scope', 'myService', Controller2])
    .service('myService', ['$log', myService]);

  function Controller1($scope, myService) {
    $scope.$watch(
      myService.getType,
      function(newValue, oldValue) {
        $scope.selectedType = myService.getType();
      }
    );
    $scope.updateType = myService.updateType;
  }

  function Controller2($scope, myService) {
    $scope.$watch(
      myService.getType, //watch the service get function for changes in return value, then update local scope
      function(newValue, oldValue) {
        $scope.selectedType = myService.getType();
      }
    );
  }

  function myService($log) {
    var _selectedType = 0;

    function _updateType(type) {
      $log.log("updateType: " + type);
      return _selectedType = type;
    }

    function _getType() {
      $log.log("getType: " + _selectedType);
      return _selectedType;
    }

    return {
      updateType: _updateType,
      getType: _getType
    }
  }
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="Controller1">
    <div>
      <input ng-model="newType" />
      <button ng-click="updateType(newType)">Update type</button>
    </div>
    Selected type in Controller 1: {{selectedType}}
  </div>
  <div ng-controller="Controller2">
    Selected type in Controller 2: {{selectedType}}
  </div>
</div>

或者,考虑以下情况(我还演示了多个模块共享,因为我在您的评论中注意到了这个可能的要求):

(function() {
  "use strict";
  
  // define a services module that can be listed as a dependency of other modules
  angular.module('myApp.services', [])
    .service('myService', ['$log', myService]);

  //here we show the module containing our controller depends on the module with the service
  angular.module('module1', ['myApp.services']) 
    .controller('Controller1', ['$scope', 'myService', Controller1]);

  angular.module('module2', ['myApp.services'])
    .controller('Controller2', ['$scope', 'myService', Controller2]);

  // this is the module being used by ng-app='myApp' to tie it all together
  // note that since the controller modules already specify their dependence on the services module,
  // we don't need to list it again here.
  angular.module('myApp', ['module1', 'module2']);

  function Controller1($scope, myService) {
    $scope.data = myService.getData(); // we pass the whole object, and scope binding expressions have a '.' in them: {{data.selectedType}}
    $scope.updateType = myService.updateType;
  }

  function Controller2($scope, myService) {
    $scope.data = myService.getData();
  }

  function myService($log) {
    var _data = {
      selectedType: 0
    };

    function _updateType(type) {
      $log.log("updateType: " + type);

      _data.selectedType = type;
    }

    function _getData() {
      $log.log("getData called:");
      $log.log(_data);

      return _data;
    }

    return {
      updateType: _updateType,
      getData: _getData
    }
  }
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="Controller1">
    <div>
      <input ng-model="newType" />
      <button ng-click="updateType(newType)">Update type</button>
    </div>
    Selected type in Controller 1: {{data.selectedType}}
  </div>
  <hr />
  <div ng-controller="Controller2">
    <div>
      <input ng-model="data.selectedType" /> &lt;- 2-way binding, no separate update function needed
    </div>
    Selected type in Controller 2: {{data.selectedType}}
  </div>
</div>

在上面的示例中,我们从服务返回一个对象。由于对象是通过引用传递的,因此任何持有对它的引用的控制器都可以看到服务中对其属性的更改。这使得 2 向绑定非常容易。

请记住,如果您替换服务中的对象而不是仅更新其属性,您将破坏控制器对其的引用(实际上,控制器将维护对旧对象的引用,但是您的服务将包含一个新服务)。在这种情况下,像 angular.extend 和/或 angular.copy 这样的辅助函数可以很容易地使用 REST API 调用返回的对象属性中的数据更新服务中的任何对象,而无需完全替换对象(从而避免破坏引用)。

【讨论】:

  • 感谢您的回答!!!我尝试了您使用手表的第一个示例。 controller1 是我的主页,controller2 是弹出页面,单击主页中的按钮时会打开。我将服务注入两个控制器,从控制器 1 更新服务中的 selectedType 变量,并在手表中检索此变量值,如您所提到的。但仍然从控制器 1 更新为 1 并且在控制器 2 中检索到的值始终为 0。
  • 乐于助人!一旦有机会,我会尝试进一步调查并更新我的。我从您对另一个答案的评论中假设您无法修改服务,因此第二个示例不是一个选项?通常问题与此有关:stackoverflow.com/questions/30126743/…
  • 我需要观察这个 selectedtype 值,如果这个变量的值发生了变化,那么应该选择那个新值来处理进一步的方法。
【解决方案2】:

我建议创建一个DataRepo 服务,该服务包含整个页面所需的所有数据。然后,您可以通过注入此服务来访问所有控制器中的相同数据:

myApp.factory('DataRepo', function() { 

    var defaultState = {
        selectedType: 1
    };

    return {
        state: angular.copy(defaultState)
    };
});

Fiddle

【讨论】:

  • 我应该使用这个现有的服务。
  • 那么重构现有服务:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-18
  • 1970-01-01
相关资源
最近更新 更多