问题
Using AngularJS 1.2.16, ui-router, and Restangular (for API services), I have an abstract state with a child state that uses multiple views. The child view accepts a URL parameter (via $stateParams) and a resolve to fetch the record from an API based on the given ID passed via the URL.
All works perfectly as you navigate throughout the site, however if you are on the given page and refresh it (Command/Ctrl+r or clicking the refresh button) or load the page directly by hitting the deep link with the ID (this is the more crucial problem) the API service is hit by the request but the promise never finishes resolving, thus the data isn't made available to the state, controller, templates, etc.
According to ui-router's documentation, controllers shouldn't be instantiated until all promises are resolved. I've searched high and low in Google and SO, read the AngularJS, Restangular, and ui-router documentation, and a multitude of blogs and tried every iteration I know to figure this out and can't find anything that points to a solution.
Here's the code in question:
company.js (controller code)
angular.module('my.company', ['ui.router', 'CompanySvc'])
.config(['$stateProvider', function config ($stateProvider) {
$stateProvider
.state('company', {
abstract: true,
url: '/company',
data: {
pageTitle: 'Company'
},
views: {
'main': {
templateUrl: 'company/companyMain.tpl.html'
}
}
})
.state('company.landing', {
url: '/{id}',
views: {
'summary': {
controller: 'CompanyCtrl',
templateUrl: 'company/companyDetails.tpl.html'
},
'locations': {
controller: 'CompanyCtrl',
templateUrl: 'company/companyLocations.tpl.html'
}
},
resolve: {
companySvc: 'CompanySvc',
// Retrieve a company's report, if the id is present
company: ['$log', '$stateParams', 'companySvc', function ($log, $stateParams, companySvc) {
$log.info('In company.landing:resolve and $stateParams is: ', $stateParams);
var id = $stateParams.id;
$log.info('In company.landing:resolve and id is: ', id);
return companySvc.getCompany(id).$promise;
// NOTE SO: this was another stab at getting the promise resolved,
// left commented out for reference
/*return companySvc.getCompany(id).then(function (response) {
return response;
});*/
}]
}
});
}
])
.controller('CompanyCtrl', ['$log', '$scope', '$state', 'company',
function CompanyCtrl ($log, $scope, $state, company) {
$log.info('In CompanyCtrl & $state is: ', $state);
$log.info('In CompanyCtrl and company data is: ', company);
$scope.reportData = company ? company : {};
$log.info('In CompanyCtrl and $scope.reportData is: ', $scope.reportData);
}
]);
companyService.js (API service code using Restangular)
angular.module('my.companyService', ['restangular']);
.factory('CompanySvc', ['$log', 'Restangular', function ($log, Restangular) {
var restAngular = Restangular.withConfig(function (Configurer) {
Configurer.setBaseUrl('/int');
});
// Object for working with individual Companies
var _companySvc = restAngular.all('companies');
// Expose our CRUD methods
return {
// GET a single record /int/companies/{id}/report
getCompany: function (id) {
$log.info('In CompanySvc.getCompany & id is: ', id);
return restAngular.one('companies', id).customGET('report').then(function success (response) {
$log.info('Retrieved company: ', response);
return response;
}, function error (reason) {
$log.error('ERROR: retrieving company: ', reason);
return false;
});
}
};
}]);
Some other points that may be added: * html5mode is true with a hashPrefix * app is being served by Apache with rewrite rules set * base href is set * this is a problem endemic to the entire application where data is being resolved in a state; I just chose this as the example
Finally, here's some output from the console:
In company.landing:resolve and $stateParams is: Object { id="d2c936fb78724880656008a5545b01ea445d4dc4"}
In company.landing:resolve and id is: d2c936fb78724880656008a5545b01ea445d4dc4
In CompanySvc.getCompany & id is: d2c936fb78724880656008a5545b01ea445d4dc4\
In CompanyCtrl & $state is: Object { params={...}, current={...}, $current={...}, more...}
In CompanyCtrl and company data is: undefined
In CompanyCtrl and $scope.reportData is: Object {}
In CompanyCtrl & $state is: Object { params={...}, current={...}, $current={...}, more...}
In CompanyCtrl and company data is: undefined
In CompanyCtrl and $scope.reportData is: Object {}
In CompanyCtrl & $state is: Object { params={...}, current={...}, $current={...}, more...}
Retrieved company: Object { $promise={...}, $resolved=false, route="companies", more...}
回答1:
Firstly just a note. If you have routing issues (like those with ui-router), instead of using a fiddle, you can just use something like pastebin to provide a single complete demo file that can be run locally, so that the route issues can be tested.
I have created one of those from your fiddle: here
The interesting thing is, that your mock demo seems to work perfectly fine with regards to routing. This makes me think that the issue lies somewhere in your production service. One thing that used to annoy me with ui-router
was the difficulty in solving resolve
bugs, as there seemed to be little to no error reporting.
If you add this to your apps run function (as I have done in the link above), you should get better resolve error output:
// handle any route related errors (specifically used to check for hidden resolve errors)
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){
console.log(error);
});
来源:https://stackoverflow.com/questions/25192598/angular-ui-router-isnt-fulfilling-state-resolve-promises-when-page-refreshes-or