Ensuring AngularJS ui-router/app waits for $http data to avoid Flash of Unstyled Content (FOUC)

My question or situation pertains to the states defined in my AngularJS application. Here is an example of how I have them structured:

$stateProvider
            .state('myApp', {
                abstract: true,
                template: '<ui-view/>'
            })
            .state('myApp.stateOne', {
                url: 'state1',
                templateUrl: '/an/views/state-1.html',
                controller: 'StateOneCtrl'
            })
            .state('myApp.stateTwo', {
                url: 'state2',
                templateUrl: '/an/views/state-2.html'
                controller: 'StateTwoCtrl'
            })
            .state('myApp.stateThree', {
                url: 'state3',
                templateUrl: '/an/views/state-3.html'
                controller: 'StateThreeCtrl'
            })

In this scenario, if I need to verify whether a user is permitted to access 'mayApp.stateThree', I typically make a backend request. This is handled by a service (in this case, named IsAllowedService). Normally, I would include the logic for this check in the .run() block within my app.js file, as shown below:

.run(['IsAllowedService', '$state', function (IsAllowedService, $state) {

        $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {

            // Check if we are trying to access myApp.stateThree and determine permission...
            if (toState.name === 'myApp.stateThree') {
                IsAllowedService.checkIfIsAllowed().then(function (resp) {
                    if(resp.allowed === false) {
                        $state.go('myApp.stateOne');
                    }
                });
            }

        });

}]);

While the above method works fine, it does not wait for the service response before loading 'mayApp.stateThree'. As a result, there is a quick display of the page before redirection occurs. I could replicate the same code in the 'StateThreeCtrl' but the flash issue persists. Is there a way to address this during state definition? For instance, something like the hypothetical code snippet below:

.state('myApp.stateThree', {
    url: '/an/state3',
    templateUrl: '/an/views/state-3.html'
    controller: 'StateThreeCtrl',
    resolve: {
        isAllowed : function () {
        IsAllowedService.checkIfIsAllowed().then(function (resp) {
            return resp;
            })
        }
    }

It is evident that directly injecting services such as $http may not be feasible, but is there a method to delay the rendering of the view / controller for 'mayApp.stateThree' until the result from

IsAllowedService.checkIfIsAllowed()
is obtained? Any guidance on structuring my application/code would be welcomed. Despite using ng-cloak in the HTML view, it did not resolve the issue!

Answer №1

It seems like you're on the right track in your application's run block, but there are a few things you can adjust to improve it. One way to enhance it is by preventing certain actions using:

  event.preventDefault(); //Prevent from going to the page

Additionally, incorporating custom data into your $states will enable you to validate conditions based on specific criteria. For example:

$stateProvider.state('home', {
  controller: 'HomeController as home',
  url: '/home',
  templateUrl: 'home.html',
  data: { roles: [ROLES.ANONYMOUS] }}); //You can set any condition here
$stateProvider.state('user', {
  controller: 'UserController as user',
  url: '/user',
  templateUrl: 'user.html',
  data: { roles: [ROLES.ADMIN, ROLES.USER] }});

To access this custom data, utilize the $stateChangeStart event:

  $rootScope.$on('$stateChangeStart', function(event, next) {
    if (!yourService.isAuthorized(next.data.roles)) {
      event.preventDefault(); //Prevent from going to the page -> avoid flickering
      $state.go('403'); //Or any other desired action
    } 
  });

The flickering issue arises when using a Promise and waiting for its fulfillment before redirecting the page. To resolve this, you can prevent the default action, authorize appropriately, and continue with your desired flow once the promise resolves.

       if (toState.name === 'myApp.stateThree') {
            event.preventDefault(); //prevent the request.
            IsAllowedService.checkIfIsAllowed().then(function(resp) {
                if (resp.allowed === false) {
                    $state.go('myApp.stateOne');
                } else { //He is allowed to go to state three.
                   $state.go('myApp.stateThree');
                } 
            }, function() { //handle server errors
              $state.go('myApp.stateOne'); //Prevent unwanted access
        });

If these conditions don't change during runtime, such as user role-based scenarios, consider fetching them upon user verification to eliminate the need for a promise altogether. Hopefully, this advice proves useful.

I previously shared a similar post here along with a working plunker.

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

"Exploring the power of AngularJS: Combining server side validation with dynamic client

Currently, I am trying to grasp the concept of declaring a form properly. My understanding is that one should simply declare the form in HTML and include ng-model directives like this: ng-model="item.name" When it comes to sending data to the server, I b ...

The div is not displaying the conditional styling as expected

I need help with mapping an array of cards wrapped in a div. I want the first, second, second-to-last, and last divs to go on a new line or take up the entire row. My project is in Vue3 and I'm using the PrimeVue component library. <div class=" ...

The exact measurement of width is not specified in the custom element that extends HTMLCanvasElement

I have created a custom element that extends a canvas, but when I try to add it to the DOM, the width appears to be undefined. Here is my code snippet. class Renderer extends HTMLCanvasElement { constructor() { super(); } } customElements.def ...

Encountering issues with saving information to MongoDB

I recently started working with the MERN stack and I am trying to save user information in MongoDB, which includes two string attributes: "name" and "role". However, I encountered an error in the browser console stating "Failed to load resource: Request t ...

Image failed to load

Issue Encountered in Browser Console: https://static.food2fork.com/pastaallavodkaa870.jpg.jpg 404 While attempting to display the image on the browser, I am uncertain if the problem lies within my code or with food2fork. Code from index.js: // Alway ...

Attach a click event handler to a D3 element

Upon loading the page, the nodeClick() method is called without any clicking action. How can I adjust it so that the nodeClick() function is only triggered when I click on the element? Here is the code snippet: var node = svg.selectAll(".node") .on( ...

Using JavaScript to create a JSON object within a table

Currently, I am facing a challenge in creating a JSON object from an HTML table using JavaScript. While I can successfully retrieve the values of each cell in JavaScript, the issue lies in organizing and retrieving them as per my requirements. Here is the ...

Using PHP script, extract information from a JSON file and populate a dropdown menu in HTML

I am attempting to extract data from a JSON file using PHP and then display this data in an HTML select tag on the front end. Below is my PHP file: <?php ini_set('display-errors', 'on'); error_reporting(E_ALL); $executionStartTim ...

Inject object into data attribute

I currently have data stored in a specific attribute like this: <div data-id=""> Within my markdown file, I also have a frontmatter variable like this: id: rick My goal is to pass that variable into the data-id attribute, which only accep ...

Display Image based on AngularJS value

Within my data, there exists a value {{catadata2.EndorsementList['0'].Rating}}. This value can be either 3, 4, or 5. Based on this value, I am looking to display the image <img src="/assets/img/rating.png" /> a certain number of times. For ...

Event Listener for Spelling Quiz Buttons: Check Correct and Incorrect Answers

I am currently in the process of developing a spelling quiz for a project website using HTML, CSS, and JavaScript. The idea is to present the user with a word that has two missing letters indicated by underscores. The user then selects the correct answer ...

Tips for adding content to several elements at once using jQuery

My HTML structure is as follows : <span class="section2 section4">hello</span> <span class="section1">World</span> <div class="tab" id="tab1"></div> <div class="tab" id="tab2"></div> <div class="tab" id= ...

Ways in which AngularJS and JQuery can be utilized

I'm a programmer experienced in JQuery and now eager to delve into the world of AngularJS for my upcoming project. I recently came across this insightful answer on how to shift from thinking in jQuery to thinking in Angular. This has prompted me to ex ...

Issue with jQuery not being able to retrieve the data from my CSS property

this is my custom style code: table.table tr td{ padding:30px; border-left: double 1px white; border-bottom: double 1px white; cursor:cell; } and below is the jQuery script I am using: $(document).ready(function () { ...

dealing with errors coming from a child asynchronous callback function

function main(){ try { subCallbackFunction(1,(err,res) =>{ if(err){ throw Error(err); } }) } catch (e) { /// Handling error from subCallbackFunction inside this catch block ////// conso ...

Conditional ngOptions in AngularJS allows you to dynamically update the options

Currently, I am working with a select box that iterates through an array of departments to identify eligible parent departments. <select class="editSelectBox" ng-model="dept.parentDepartment" ng-options="dept as dept.name for dept in depts track by de ...

Is there a way to dynamically access BEM-style selectors using CSS modules?

For instance, I have this specific selector in my App.module.css file: .Column--active I want to access this selector from the App.js file in React using CSS modules. After importing all selectors from the CSS file as import styles from './App. ...

What is the best way to keep a bootstrap navbar fixed at the top when scrolling? (It's a bit tricky)

Check out this image of my website header. HERE Is there a way to achieve a smooth scrolling effect for the blue navbar as I scroll down the page? (Specifically just the navbar, excluding the logo and social media elements). Using position:fixed; does ...

Challenges with rendering items in a FlatList component in React Native

I'm currently working on transferring data from a data.json file to video.js <Image source={{ uri: video.snippet.thumbnails.medium.url }} style={{ height: 200 }} /> and I want this file to be rendered in a flatlist <FlatList showsHorizo ...

Is it advisable to use npm devDependencies in a production environment?

While reviewing the package.json file for one of our products at work, I noticed that the SDK uses socket.io for a crucial function even though socket.io-client is listed as a devDependency. Despite this discrepancy, the SDK works flawlessly for our clie ...