控制器中的AngularJS SET服务变量,并在其他任何地方使用GET,而不使用$watch



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

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

在全局控制器中,我调用我的$api工厂,该工厂发出http请求(带有promise(以获取和设置公司选项。我只做过一次。

.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、promise、$rootScope等。但除了在我获得值的每个控制器和指令中使用$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. 我可以在服务中使用一次$watch,而不是在每个控制器/指令中使用$watch吗
  3. 如果"options"为空,那么在服务内部调用http请求是否更有意义?这样我就可以用诺言了?(但我不喜欢这个选项,因为有其他功能,我最好在全局控制器中获取/设置companyOptions(

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

我决定在ngStorage持有公司期权(https://github.com/gsklee/ngStorage)而不是服务。

所以这个:

companyService.setOptions($scope.companyOptions)

更改为:

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

然后,我在以下代码的帮助下使用了全局路由解析,这样这段代码就可以在实际路由发生之前工作。(工厂被称为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)
}
}])

这是工厂本身,我也在那里观察公司选项的设置。并在页面准备就绪时路由到页面:

.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

最新更新