6

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?

1
  • Did you ever get this worked out? I'm running into something very similar and am stuck :( Commented Dec 12, 2014 at 20:44

1 Answer 1

2

It's better to use $urlRouterProvider to handle this exceptions

app.config([
    "$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/404');
        // define states        
}]);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.