How to wait for resources to be loaded


Tags: javascript,jquery,css,json,angularjs

Problem :

I'm writing an AngularJS application and I'm trying to achieve certain things, but since I'm very new to Angular, I want to have the opinion of some AngularJS experts.

I'm creating a control suite in fact in AngularJS and that consists out of 2 parts, a loading screen and a showing screen, both defined in HTML.

The data which I need to manipulate is stored in JSon files. To give you an idea, here's the first JSon file:

{
  "Styles": [
    { "name": "Blue", "stylesheet": "/Resources/Stylesheets/Styles/Blue/OfficeUI.Style.Blue.min.css" },
    { "name": "Green", "stylesheet": "/Resources/Stylesheets/Styles/Green/OfficeUI.Style.Green.min.css" },
    { "name": "LightBlue", "stylesheet": "/Resources/Stylesheets/Styles/LightBlue/OfficeUI.Style.LightBlue.min.css" },
    { "name": "Orange", "stylesheet": "/Resources/Stylesheets/Styles/Orange/OfficeUI.Style.Orange.min.css" },
    { "name": "Purple", "stylesheet": "/Resources/Stylesheets/Styles/Purple/OfficeUI.Style.Purple.min.css" },
    { "name": "Red", "stylesheet": "/Resources/Stylesheets/Styles/Red/OfficeUI.Style.Red.min.css" },
    { "name": "Turquoise", "stylesheet": "/Resources/Stylesheets/Styles/Turquoise/OfficeUI.Style.Turquoise.min.css" }
  ],
  "DefaultStyle": "LightBlue",

  "Themes": [
    { "name": "No Background", "stylesheet": "/Resources/Stylesheets/Themes/No Background/OfficeUI.Themes.No-Background.min.css" },
    { "name": "Calligraphy", "stylesheet": "/Resources/Stylesheets/Themes/Calligraphy/OfficeUI.Themes.Calligraphy.min.css" },
    { "name": "Circles And Stripes", "stylesheet": "/Resources/Stylesheets/Themes/Circles-And-Stripes/OfficeUI.Themes.Circles-And-Stripes.min.css" },
    { "name": "Circuit", "stylesheet": "/Resources/Stylesheets/Themes/Circuit/OfficeUI.Themes.Circuit.min.css" },
    { "name": "Clouds", "stylesheet": "/Resources/Stylesheets/Themes/Clouds/OfficeUI.Themes.Clouds.min.css" },
    { "name": "Doodle Circles", "stylesheet": "/Resources/Stylesheets/Themes/Doodle-Circles/OfficeUI.Themes.Doodle-Circles.min.css" },
    { "name": "Doodle Diamonds", "stylesheet": "/Resources/Stylesheets/Themes/Doodle-Diamonds/OfficeUI.Themes.Doodle-Diamonds.min.css" },
    { "name": "Geometry", "stylesheet": "/Resources/Stylesheets/Themes/Geometry/OfficeUI.Themes.Geometry.min.css" },
    { "name": "Lunchbox", "stylesheet": "/Resources/Stylesheets/Themes/Lunchbox/OfficeUI.Themes.Lunchbox.min.css" },
    { "name": "School Supplies", "stylesheet": "/Resources/Stylesheets/Themes/School-Supplies/OfficeUI.Themes.School-Supplies.min.css" },
    { "name": "Spring", "stylesheet": "/Resources/Stylesheets/Themes/Spring/OfficeUI.Themes.Spring.min.css" },
    { "name": "Stars", "stylesheet": "/Resources/Stylesheets/Themes/Stars/OfficeUI.Themes.Stars.min.css" },
    { "name": "Straws", "stylesheet": "/Resources/Stylesheets/Themes/Straws/OfficeUI.Themes.Straws.min.css" },
    { "name": "Tree Rings", "stylesheet": "/Resources/Stylesheets/Themes/Tree-Rings/OfficeUI.Themes.Tree-Rings.min.css" },
    { "name": "Underwater", "stylesheet": "/Resources/Stylesheets/Themes/Underwater/OfficeUI.Themes.Underwater.min.css" }
  ],
  "DefaultTheme": "Geometry",
  "Configuration": "/Resources/Data/Application.json",
  "Controls": [
    { "Name": "Ribbon", "ConfigurationFile": "/Configuration/Application/OfficeUI.Ribbon.config.json" }
  ]
}

As you see, the file does contain some references to stylesheets which needs to be embedded in the page dynamiccaly.

Now, let's move to the AngularJS part.

First of all, I have the definition of my module:

var OfficeUI = angular.module('OfficeUIApplication', ['ngSanitize']);

Then, I do have a service which loads the JSon file defined above:

OfficeUI.factory('OfficeUIConfigurationService', function($http) {
    // Defines the object that this service needs to return.
    return {
        getOfficeUIConfiguration: function() {
            // Check if the location of the file can be found somewhere. If it cannot be found, throw an error.
            if (typeof $.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation === 'undefined' || $.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation == '') {
                OfficeUICore.Exceptions.officeUIConfigurationException('The OfficeUI Configuration file is not defined.');
            }

            // Returns the 'httpPromise' which is required for further processing.
            return $http.get($.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation)
                .then(function (response) {
                    return {
                        Styles: response.data.Styles,
                        DefaultStyle: response.data.DefaultStyle,
                        Themes: response.data.Themes,
                        DefaultTheme: response.data.DefaultTheme,
                        Configuration: response.data.Configuration,
                        Controls: response.data.Controls
                    };
                }, function(error) { OfficeUICore.Exceptions.officeUILoadingException('The OfficeUI Configuration file: \'' + $.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation + '\' could not be loaded.'); }
            );
        }
    }
});

Then, I'm having my controller:

OfficeUI.controller('OfficeUIController', function(OfficeUIConfigurationService, $scope, $http) {
    $scope.isInitialized = false;           // Indicates that the entire OfficeUI application has been loaded.
    $scope.loadingScreenLoaded = false;     // Indicates that the data for the loading screen has been loaded.

    // Initialize all the required components for the website.
    Initialize();

    function Initialize() {
        OfficeUIConfigurationService.getOfficeUIConfiguration().then(function(data) {
            var foundStyles = JSPath.apply('.{.name == "' + data.DefaultStyle + '"}', data.Styles);
            var foundThemes = JSPath.apply('.{.name == "' + data.DefaultTheme + '"}', data.Themes);

            $scope.Style = foundStyles[0].stylesheet;
            $scope.Theme = foundThemes[0].stylesheet;

            // Set a value that indicates that the loading screen has been loaded. So, at this point, the loading screen
            // can be rendered.
            $scope.loadingScreenLoaded = true;

            // Returns the 'httpPromise' which is required for further processing.
            $http.get(data.Configuration)
                .then(function (response) {
                        $scope.Title = response.data.Title;
                        $scope.Icons = response.data.Icons;
                }, function(error) { OfficeUICore.Exceptions.officeUILoadingException('The OfficeUI application definition file: \'' + data.Configuration + '\' could not be loaded.'); }
            );
        });

        setTimeout(function() {
            $scope.isInitialized = true;
            $scope.$apply();
        }, 2000);
    }
});

Note: I do set a timeout here, to make sure that the loading screen is being displayed for 2 seconds.

In this controller, you find the following piece of code:

OfficeUIConfigurationService.getOfficeUIConfiguration().then(function(data) {
    var foundStyles = JSPath.apply('.{.name == "' + data.DefaultStyle + '"}', data.Styles);
    var foundThemes = JSPath.apply('.{.name == "' + data.DefaultTheme + '"}', data.Themes);
    $scope.Style = foundStyles[0].stylesheet;
    $scope.Theme = foundThemes[0].stylesheet;
    // Set a value that indicates that the loading screen has been loaded. So, at this point, the loading screen
    // can be rendered.
    $scope.loadingScreenLoaded = true;
    // Returns the 'httpPromise' which is required for further processing.
    $http.get(data.Configuration)
        .then(function (response) {
                $scope.Title = response.data.Title;
                $scope.Icons = response.data.Icons;
        }, function(error) { OfficeUICore.Exceptions.officeUILoadingException('The OfficeUI application definition file: \'' + data.Configuration + '\' could not be loaded.'); }
    );
});

What this does is, from my loading service, retrieve and parse the JSon file, and based on the values in this file, assign a value to Style and Theme, which both are scopes objects.

In my HTML, this is being rendered like this (in the head section of the file):

<link rel="stylesheet" href="#" data-ng-href="{{Style}}" />
<link rel="stylesheet" href="#" data-ng-href="{{Theme}}" />

This allows me to change the look and feel of my application dynamiccaly (by calling a method which change the scope value).

However, there can be a flickering issue. When the Json file is loaded and parsed, I assign a value to loadingScreenLoaded which makes sure that the loading screen is being showed:

<div class="loading-area center-screen no-select" data-ng-if="loadingScreenLoaded && !isInitialized">

However, at this particular case, it might be that the CSS file is still loading.

So the question is, how to not show the loading div on the page, until all the resources have been loaded (CSS, ...)

Also, if possible, is there a way to do the same with ng-include directive, images, ...

Kind regards,



Solution :

It's not recommended to use timeout, I cannot expect that your resources will be ready after 2000

setTimeout(function() {
        $scope.isInitialized = true;
        $scope.$apply();
    }, 2000);

I will recommend you to use file and module loader library. Try to use angular with requirejs

See this example of using angularjs + requirejs


    CSS Howto..

    How to set stylesheet programmatically in an ASP.NET MVC 2 project?

    How to write CSS code without using :not selector?

    How to remove excess space added with \n

    How to assign custom CSS to Sharepoint site

    Show hidden image with jQuery

    How to get a label under an underlined word in css? [closed]

    How to convert CSS class to id?

    How to compile sass / scss without creating map files

    How to change a css element based on other element

    How do I style DIVs inside a checkbox label based on if it is checked or not?

    How to use a Drive hosted css to customize the receiver?

    Integration of CSS, Javascript and html ,,,howto

    c# cassette - how to create different css bundles for different pages

    Why is the icon shown in some browsers while other it is not

    How to put text over Image

    How do front end devs bundle and minify files?

    How to give slide down effect when hover?

    how to crop images that has any size using css

    Showing the selected value on the handler of range input as the value changes

    How do I apply css code for svg in google api charts

    How do I stop richfaces adding borders to panels and calendars?

    How to vertically align the baseline of text to a set point in HTML/CSS

    CSS isn't shown when HTML file is opened in Word

    How to change my css code to fit the footer to the bottom of the page for any size of monitor?

    How to achieve this awesome CSS animation

    How to change the opacity of image on hover using css

    How to load up CSS files using Javascript?

    Show/Hide images based on tab selection

    How to disable caching of static assets like .css and .js in JSF2?

    How to make a CSS/javascript feature like this website? [closed]