AngularJS 在控制器中设置服务变量,并在没有 $watch 的情况下在其他地方使用 GET 它

AngularJS SET service variable in controller, and use GET it everywhere else without $watch

这是我设置和获取值的基本服务:

.service('companyService', [ function () {
  var self = this
  self.options = {}
  function CompanyService () {
    self.setOptions = function (newObj) {
    self.options = newObj
    }
  }
  return CompanyService()
}])

在全局控制器中,我调用我的 $api 工厂,它发出一个 http 请求(有承诺)来获取和设置公司选项。我只这样做过一次。

.controller('global', ['$scope', '$http', '$api', '$location', '$translate', '$rootScope', '$timeout', '$filter', 'toastr', '$window', 'flag', 'companyService', function ($scope, $http, $api, $location, $translate, $rootScope, $timeout, $filter, toastr, $window, flag, companyService) {
$api('GetCompanyOptions', {})
    .then(function (response) {
      $scope.companyOptions = response.data
      // doing stuff with the response first
      // ...
      // and setting the value to companyService
      companyService.setOptions($scope.companyOptions)
    })
}])

现在几乎在每个控制器和指令中我都想使用这个值。但是因为 http 调用需要一段时间,我在时间上遇到了很多问题,所以有时我会得到以下空值:(是的,在 html 里面它会自动使用 $apply 并且变量不为空,但它在控制器内部)

$scope.companyOptions = companyService.options

我尝试了很多解决方案,例如使用 $watch、$timeout、promises、$rootScope 等。但是 none 除了在每个控制器中使用 $watch 和我获取值的指令外,其他都有效:

$scope.$watch(function () { return companyService.options }, function (newVal) {
  // checking if companyService.options is still empty or not
  if (!$.isEmptyObject(newVal)) {
    // Now the options is filled, do some stuff...
  }
})

所以我的问题是:

  1. 在每个控制器中使用 $watch 都可以。但是有点乱,有没有办法去掉它们?
  2. 我可以在服务中使用一次,而不是在每个 controller/directive 中使用 $watch 吗?
  3. 如果 'options' 为空,在服务内部调用 http 请求是否更有意义?这样我就可以使用 promise 了吗? (但我不喜欢这个选项,因为其他功能对我来说更好 get/set companyOptions inside global controller)

在尝试了很多解决方案后,我决定以下最适合我。我希望它可能对其他人有用。

我决定在 ngStorage (https://github.com/gsklee/ngStorage) 而不是服务中保留公司选项。

所以这个:

companyService.setOptions($scope.companyOptions)

改为:

$scope.$storage.companyOptions = $scope.companyOptions

然后我在下面的代码的帮助下使用了一个全局路由解析,这样这段代码就可以工作了'before'实际的路由发生了。 (工厂称为 checkToken 因为我在这里也做了一个 http 请求来检查用户令牌是否有效):

  Routes.config(['$routeProvider', function ($routeProvider) {
  var originalWhen = $routeProvider.when
  $routeProvider.when = function (path, route) {
    route.resolve || (route.resolve = {})
    angular.extend(route.resolve, {
      checkToken: ['$checkToken', function ($checkToken) {
        return $checkToken.checkToken()
      }]
    })
    return originalWhen.call($routeProvider, path, route)
  }
}])

这是工厂本身,我也在其中观察要设置的 companyOptions。准备就绪后路由到页面:

 .factory('$checkToken', ['$q', '$timeout', '$location', '$api', '$rootScope', '$localStorage', function ($q, $timeout, $location, $api, $rootScope, $localStorage) {
  return {
    checkToken: function () {
      var deferred = $q.defer()
      $api('IsTokenValid', {})
      .then(function (response) {
          // some unrelated codes here...
          // watching companyoptions in localStorage
          $rootScope.$watch(function () { return $localStorage.companyOptions }, function (newVal) {
            if (!$.isEmptyObject(newVal)) {
              // now that we have companyOptions, resolve and go to page
              deferred.resolve('go to page!')
            }
          }, true)
      })
      return deferred.promise
    }
  }
}])

最后感谢这个解决方案,在我的控制器中,这个:

$scope.$watch(function () { return companyService.options }, function (newVal) {
  // checking if companyService.options is still empty or not
  if (!$.isEmptyObject(newVal)) {
    // Now the options is filled, do some stuff...
  }
})

变成这样,我去掉了公司服务工厂:

$scope.companyOptions = $scope.$storage.companyOptions