Dealing with 404 Errors in AngularJS using ui-router's resolve feature

As a newcomer to AngularJS and ui-router, I am currently facing the challenge of handling 404 errors for resources not found. My goal is to display an error message without changing the URL in the address bar.

Here is how I have configured my states:

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"
            });
    }
]);

(Although I'm using TypeScript, I converted the above to pure JavaScript)

If, for example, I visit the following URL:

http://localhost:12345/listings/bef8a5dc-0f9e-4541-8446-4ebb10882045
It should navigate to the listings.details state. However, if that particular resource does not exist and the promise from the resolve function fails with a 404 error, I handle it as follows:

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 });
            }
        });
    }
]);

The objective here is to transition to the listings.notFound state while keeping the destination URL unchanged in the address bar. Using a relative path allows for reusing this logic for other resources.

Unfortunately, I encounter an exception:

Path '^.notFound' not valid for state 'listings.details'

This issue arises because the toState argument provided by the $stateChangeError event lacks information about its parent; specifically, toState.parent is undefined. Trying

relative: $state.get(toState.name)
also proves ineffective since ui-router once again returns state.self.

I prefer to avoid maintaining a list of absolute paths and repeat the navigation logic for the state hierarchy. Is there a different, more appropriate way to handle 404 errors? If not, what would be the best approach?

Answer №1

To effectively manage these exceptions, it is recommended to employ $urlRouterProvider.

app.config([
    "$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/404');
        // specify states        
}]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adding information into material-ui dropdown using React JS

I could use some assistance with populating data into a Dropdown using material-ui in React. I am new to React and unsure about how to achieve this. I know that I can pass props to the dropdown, but it's not very clear to me. Here is my current code: ...

Avoid page refreshing when modifying app.js in React

Today is only my second day using React and I started by creating a React app with "npx create-react-app." However, when I tried to make changes to the app.js file, they didn't appear on the page even after refreshing the browser multiple times. (My n ...

What is the best way to incorporate npm packages into my projects?

Lately, I've been heavily relying on nodejs, but I keep running into the same issue. With so many projects available and a plethora of npm packages to choose from, it's frustrating that every time I try npm install --save some-package, I struggle ...

Sending template reference from one Angular component to another

I have a main grid component that includes smaller grid-item components. The majority of these grid items navigate to a specific route when clicked. However, there is one particular item that should open a modal window instead of navigating. Is there a wa ...

How the React Component Class Executes OnChange Event in a Closure

When working on my React code, I found myself creating a closure by calling "onChange." class CityInput extends React.Component { constructor( props ){ super( props ); this.state = { city : "", country : "" ...

TeamCity reported that PhantomJS was not captured within 60000 milliseconds, prompting it to terminate

While running tests in my CI environment, I've encountered an issue. The configuration runs smoothly on MacOS 10.11.6 (El Capitan) with Node v6.0.0 / npm 3.8.6. However, on a TeamCity 9.1.6 agent running Windows with Node v4.2.2 / npm 2.14.7, it fails ...

Can a single file in NextJS 13 contain both client and server components?

I have a component in one of my page.tsx files in my NextJS 13 app that can be almost fully rendered on the server. The only client interactivity required is a button that calls useRouter.pop() when clicked. It seems like I have to create a new file with ...

A jQuery component with built-in event triggers

Here's an example that illustrates the concept: a widget needs to utilize its own method as a callback: $.widget("custom.mywidget", { _create: function() { this.invoke("mymodule", "myaction", {arg: this.options.value}, this.parseData); ...

Efficient Local Database with Javascript

When storing a substantial amount of data, such as a big hashmap in JavaScript, what would be the optimal format for quick retrieval while also supporting Unicode? Would XML or JSON be better suited for this purpose? ...

Can someone share with me the best practices for implementing @HostListener within a method in my Angular 16 project?

Currently, I've been involved in developing a Single Page Application using Angular 16, TypeScript, and The Movie Database (TMDB). My task at hand is to implement the "infinite scroll" functionality on a particular component. To achieve this, I have ...

Eliminating repeated keys from an array of objects

I'm dealing with an array of objects that looks like this let array = [ { sector: "adad" }, { sector: "adadasdsd" }, { sector: "sdsdsd" }, { origin: "sdfsf" }, { destination: "dfsfsdf" } ]; My goal is to trans ...

The AngularJS app.run function fails to initialize

I am encountering a problem with app.run(). On the main page, app.run() is functioning properly. However, when I click on the Events menu button and navigate to the events.html page, app.run() does not work initially. It only starts working after I reload ...

Is it possible to create a hyperlink in the <button> element?

Having been immersed in HTML5 for quite a while now, I recently encountered a challenge while working on my login/register page project. I wanted to create a button that would redirect me to another HTML page upon clicking. While I am familiar with the < ...

Navigate to the subsequent field in an HTML5 form without any manual intervention

I have created the following HTML5 form: <form> <input type="text" name="orderno" /> <input name="picture" id="img" type="file" accept="image/*" capture="camera" /> <input class="btn-success" type="submit" name="submit" value="Uplo ...

Implementation of Gallows Game

SITUATION Recently, I took on the challenge of creating a "HANGMAN" game using JavaScript and HTML exclusively for client-side machines. The logical part of the implementation is complete, but I am facing a hurdle when it comes to enhancing the aesthetics ...

What is it about that that ticks off so many different boxes?

Hey there! I've been working on creating checkboxes within next js that iterate through each filter and its options. Fortunately, I managed to get it up and running smoothly. However, I'm encountering an issue where checking one option in a speci ...

Modify the placeholder HTML once a username has been submitted

In order to maximize efficiency, I have included an input box with a placeholder that reads: <input id="username-search" placeholder="explore another user's work"> Once the username is entered, I want to modify the placeholder text to somethin ...

JQuery .click Event doesn't center elements even with transform-origin adjustment

In the JSfiddle provided below, you can see that after a click event occurs, two span (block) elements rotate 45deg to form an "X". However, both elements are slightly shifted left, creating an off-center "X" relative to the parent's true center-origi ...

How can I use angular-ui bootstrap's typeahead feature to pull data from a JSON file and populate two separate input fields with the retrieved values

I implemented an autocomplete feature using a json file in an input field. The json file contains multiple attributes, and I want to display different attributes in separate input fields. For example, one input should show the "driver_name" and another inp ...

Utilizing Vue.js to connect with a Node.js server

After setting up a basic Node.js server, the following code is running successfully: var http = require('http'); var server = http.createServer(); server.on('request', function(req, res) { res.writeHead(200, { 'content ...