我的AngularJS单页面应用程序中有一个工厂,它根据JSON文件解析给定日期,以便在季节中返回季节和周数。我目前在每个方法$http.get('content/calendar.json').success(function(data) {...
中调用两次JSON文件。
无论有多少方法,我怎样才能将调用分解出来?
emmanuel.factory('DayService', function($http, $q){
var obj = {};
obj.season = function(d){
// receives a mm/dd/yyyy string parses against Calendar service for liturgical season
d = new Date(d);
var day = d.getTime();
var promise = $q.defer();
var temp;
$http.get('content/calendar.json').success(function(data) {
for (var i=0; i<data.calendar.seasons.season.length; i++){
var start = new Date(data.calendar.seasons.season[i].start);
var end = new Date(data.calendar.seasons.season[i].end);
end.setHours(23,59);
//sets the time to be the last minute of the season
if (day >= start && day <= end){
//if given time fits within start and end dates in calendar then return season
temp = data.calendar.seasons.season[i].name;
//console.log(temp);
promise.resolve(temp);
break;
}
}
});
return promise.promise;
}
obj.weekInSeason = function(d){
//receives a date format mm/dd/yyyy
var promise = $q.defer();
$http.get('content/calendar.json').success(function(data) {
for (var i=0; i<data.calendar.seasons.season.length; i++){
d = new Date(d);
var day = d.getTime();
var end = new Date(data.calendar.seasons.season[i].end);
end.setHours(23,59);
end = end.getTime();
var diff = end - day;
if (parseFloat(diff) > 0){
var start = new Date(data.calendar.seasons.season[i].start);
start = start.getTime();
var startDiff = day - start;
var week = parseInt(startDiff /(1000*60*60*24*7))+1;
promise.resolve(week);
break;
}
}
});
return promise.promise;
}
obj.getData = function (d) {
console.log('DayService.getData')
console.log(today)
var data = $q.all([
this.season(d),
this.weekInSeason(d)
]);
return data;
};
return obj;
});
答案 0 :(得分:2)
此解决方案假定content/calendar.json
永远不会更改。
我有 answered a question ,它可以帮助您解决这个问题。基本上,您必须在应用程序引导之前获取所有必需的配置/设置。手动引导应用程序,这意味着您必须删除html中的ng-app
指令。
步骤:
[ 1 ]按照我上面提到的已回答的问题中的说明创建 bootstrapper.js
。基本上,它应该如下所示(注意:如果您需要在应用程序之前在应用程序中添加更多设置,则可以在urlMap
中添加更多配置URL):
angular.injector(['ng']).invoke(function($http, $q) {
var urlMap = {
$calendar: 'content/calendar.json'
};
var settings = {};
var promises = [];
var appConfig = angular.module('app.settings', []);
angular.forEach(urlMap, function(url, key) {
promises.push($http.get(url).success(function(data) {
settings[key] = data;
}));
});
$q.all(promises).then(function() {
bootstrap(settings);
}).catch(function() {
bootstrap();
});
function bootstrap(settings) {
appConfig.value('Settings', settings);
angular.element(document).ready(function() {
angular.bootstrap(document, ['app', 'app.settings']);
});
}
});
[ 2 ]假设主模块的名称在 app
中为app.js
:
angular.module('app', [])
.factory('DayService', function(Settings){
var calendar = Settings.$calendar,
season = calendar.seasons.season,
obj = {};
obj.season = function(d){
var day = new Date(d).getTime(),
start, end, value;
for (var i = 0; i < season.length; i++){
start = new Date(season[i].start);
end = new Date(season[i].end);
end.setHours(23,59);
if (day >= start && day <= end){
value = season[i].name;
break;
}
}
return value;
};
obj.weekInSeason = function(d){
var day = new Date(d).getTime(),
end, diff, start, startDiff, week;
for (var i = 0; i < season.length; i++){
end = new Date(season[i].end);
end.setHours(23,59);
end = end.getTime();
diff = end - day;
if (parseFloat(diff) > 0){
start = new Date(season[i].start);
start = start.getTime();
startDiff = day - start;
week = parseInt(startDiff /(1000*60*60*24*7))+1;
break;
}
}
return week;
};
return obj;
});
[ 3 ]控制器用法(示例):
angular.module('app')
.controller('SampleController', function(DayService) {
console.log(DayService.season(3));
console.log(DayService.weekInSeason(3));
});
另一个注意事项:使用.run()
检查是否Settings === null
- 如果这是真的,您可以直接转到错误页面或显示问题的任何页面(这意味着应用程序引导但是其中一个请求的配置失败了。)
<强>更新强>
我检查了您提供的链接,似乎您使用的版本为AngularJS v1.0.8
,其.catch()
承诺实施中没有$q
方法。
在解决此问题时,您需要考虑以下选项:
-1将您使用的AngularJS版本更改为最新的稳定版本1.2.23。 请注意,此选项可能会破坏一些高度依赖于您正在使用的版本的代码。
-2更改此块:
$q.all(promises).then(function() {
bootstrap(settings);
}).catch(function() {
bootstrap();
});
为:
$q.all(promises).then(function() {
bootstrap(settings);
}, function() {
bootstrap();
});
如果您已经拥有依赖于当前使用的AngularJS版本的现有代码,则此选项更安全但我建议您更改为当前的稳定版本,因为它具有比您当前使用的更多的设施和修复程序。 / p>
答案 1 :(得分:1)
使用您的范围和工厂关闭来存储对http调用的响应值。我创建了一个名为calData
的对象,它恰好是一个承诺!
这使您能够在第一次调用工厂时通过运行IIFE(这是一个名为initService
的函数)来解决一些问题,并且所有内容都链接在一起以在数据之后解析加载。
.factory('dayService', function dayServiceFactory($http, $q){
var getCalData = $q.defer();
var calData = gettingData.promise; // null/undefined until _loadData is called and resolved
function _loadData(){
var deferred = $q.defer();
$http.get('content/calendar.json').success(function(data) {
calData.seasons = data.calendar.seasons; // your code seems to always use at least calendar.seasons, so easier to assign that
deferred.resolve(data);
});
return deferred.promise;
}
// this function will automatically run and load data the first time the factory is executed
(function initService(){
_loadData().then(){
// here is where you will build all your functions to assign properties to calData.seasons or any other child property of calData;
calData.getSeason = function(){
for (var i=0; i<data.calendar.seasons.season.length; i++){
// code here
}
}// function to get day using calData.seasons
calData.weekInSeason = function(){}
getCalData.resolve(); // this resolves the data in the outer scope
}
}());
return calData; // returns the promise, and will execute the first time called
});
要在控制器中使用它,请确保在实例化控制器之前解析服务,或者使用控制器,在解析后使用数据分配。 (绑定值将在解决后自动更新)
dayService.then(function(){
// now you can use this:
var week = dayService.weekInSeason();
})
答案 2 :(得分:1)
您可以在getData
方法中创建用于获取日历数据和链承诺的单独方法:
emmanuel.factory('DayService', ['$q', '$timeout', '$log',
function($q, $timeout, $log) {
return {
season: season,
weekInSeason: weekInSeason,
getData: getData
};
function season(d) {
$log.log('season called');
return getCalendar(d).then(function(calendar) {
return getSeason(d, calendar);
});
}
function weekInSeason(d) {
$log.log('weekInSeason called');
return getCalendar(d).then(function(calendar) {
return getWeekInSeason(d, calendar);
});
}
function getData(d) {
$log.log('getData called');
return getCalendar(d).then(
function(calendar) {
return $q.all({
season: getSeason(d, calendar),
weekInSeason: getWeekInSeason(d, calendar)
});
}
);
}
function getSeason(date, calendar) {
$log.log('getSeason called');
return {
date: date,
calendar: calendar,
method: 'getSeason'
};
}
function getWeekInSeason(date, calendar) {
$log.log('getWeekInSeason called');
return {
date: date,
calendar: calendar,
method: 'getWeekInSeason'
};
}
function getCalendar(d) {
$log.log('getCalendar called');
var deferred = $q.defer();
$timeout(function() {
deferred.resolve(12345);
}, 2000);
return deferred.promise;
}
}
]);
此外,如果在应用程序生命周期内calendar.json没有更改,您可以按照@runTarm的建议缓存calendar.json
ajax请求结果