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...
}
})
所以我的问题是:
- 在每个控制器中使用 $watch 都可以。但是有点乱,有没有办法去掉它们?
- 我可以在服务中使用一次,而不是在每个 controller/directive 中使用 $watch 吗?
- 如果 '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
这是我设置和获取值的基本服务:
.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...
}
})
所以我的问题是:
- 在每个控制器中使用 $watch 都可以。但是有点乱,有没有办法去掉它们?
- 我可以在服务中使用一次,而不是在每个 controller/directive 中使用 $watch 吗?
- 如果 '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