I'm a beginner with AngularJS and ui-router, and am trying to handle 404s on resources not found. I would like an error to be displayed, without changing the URL in the address bar.
I have configured my states as such:
app.config([
"$stateProvider", function($stateProvider) {
$stateProvider
.state("home", {
url: "/",
templateUrl: "app/views/home/home.html"
})
.state("listings", {
abstract: true,
url: "/listings",
templateUrl: "app/views/listings/listings.html"
})
.state("listings.list", {
url: "",
templateUrl: "app/views/listings/listings.list.html",
})
.state("listings.details", {
url: "/{id:.{36}}",
templateUrl: "app/views/listings/listings.details.html",
resolve: {
listing: [
"$stateParams", "listingRepository",
function($stateParams, repository) {
return repository.get({ id: $stateParams.id }).$promise;
}
]
}
})
.state("listings.notFound", {
url: "/404",
template: "Listing not found"
});
}
]);
(I'm actually using TypeScript, but I tried to change the above to be pure JavaScript)
If, say, I navigate to the following url:
http://localhost:12345/listings/bef8a5dc-0f9e-4541-8446-4ebb10882045
That should open the listings.details state.
However if that resource does not exist, the promise returned from the resolve function will fail with a 404, which I catch here:
app.run([
"$rootScope", "$state",
function($rootScope, $state) {
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
event.preventDefault();
if (error.status === 404) {
$state.go("^.notFound", null, { location: true, relative: toState });
}
});
}
]);
What I'm trying to do here is to go to the listings.notFound state, without changing the destination URL in the address bar. I use a relative path because I would like to re-use this logic for other resources.
However, I get an exception:
Path '^.notFound' not valid for state 'listings.details'
This error happens because the toState argument given by the $stateChangeError event does not know its parent, i.e. toState.parent is undefined.
In the transitionTo function of ui-router, I can see that the object given as argument is to.self
, which only provides a subset of the information.
Using relative: $state.get(toState.name)
also doesn't help, because internally ui-router once again returns state.self
I would like to avoid maintaining a list of absolute paths, and rewrite the logic for navigating in the state hierarchy (no matter how simple it is, DRY and all that).
Am I going about it wrong, is there another proper way of handling 404? If not, what is the best approach?
It's better to use $urlRouterProvider
to handle this exceptions
app.config([
"$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/404');
// define states
}]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With