Loading screen for Meteor app

I was thinking how could I make the loading screen hit the client screen right after navigating the URL to my webpage.

At the moment i have a DIV mask+spinner inside my template, which is visible as a default in .css file and hidden by jQuery when all subscibings are done…This works well, but when hitting the URL, Iron Router takes some time…

at the moment:

typing URL------2sec delay with white background----my loading screen 2sec delay— my page

Since you’re using Iron Router, have you looked into using waitOn combined with the loadingTemplate option?

Yes I have tried and same thing. LoadingTemplate appears sometimes just “1ms” before div mask, so it will not hit the browser any faster

You can use https://github.com/meteorhacks/meteor-inject-initial to inject HTML right when the page loads. Or you can just fork https://github.com/meteor/meteor/tree/devel/packages/boilerplate-generator and modify boilerplate_web.browser.html.

For Meteor 1.3 - Make something like /client/loader.html and I think it’ll display before all the template parsing happens.

I ran across this thread and use that trick for injecting my <head> element. I think you could use the same trick to place a loading spinner.

  1. I installed meteor-inject-initial
  1. added the following to the server-side
Inject.rawModHtml('inject a script at the beginning of the head', function(html) {
            return html.replace('<head>', '<head><script></script><style></style><div id="loading" style="display:flex; align-items: center;  justify-content: center;position:fixed; width:100%; height:100vh;background:white;z-index:10;"><div id="loader_inner">loading</div></div>');
        });
1 Like

How do you remove it?

I tried this:

Inject.rawModHtml('inject a script at the beginning of the head', function(html) {
    return html.replace('<head>', '<head><script></script><style></style><div id="loading" style="display:flex; align-items: center;  justify-content: center;position:fixed; width:100%; height:100vh;background:white;z-index:10;"><div id="loader_inner">loading</div></div>');
});



if (Meteor.isClient) {
    Meteor.startup(function() {
        setTimeout(function() {
            $("#loading").fadeOut(500, function() { $("#loading").remove(); });
        }, 500);
    });
}

just found this thread: [SOLVED] Display a Spinner while your App Loads

My Iron router does 5/6 subcribes for my app, the last one is inside onRendered tempalate which triggers jQuery hide when succesful. This was the most easiest way for me, as I have not had time to think of the best solution yey

UPDATE: moved it into a package and now it works… need to do some more research on loading order, packages, and startup function.


thanks… I can’t get the following to work unfortunately.

added meteorhacks:inject-initial

I have this in a server file:

if (Meteor.isServer) {
    Inject.rawHead("loader", Assets.getText('loader.html'));
}

if (Meteor.isClient) {
    Meteor.startup(function() {
        setTimeout(function() {
            $("#inject-loader-wrapper").fadeOut(500, function() { $(this).remove(); });
        }, 500);
    });
}

then I have this in private/loader.html:

<div id="inject-loader-wrapper">
    <style type="text/css">
        #showbox {
            background-color: #ffffff;
        }
        #showbox {
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            padding: 30%;
        }
        #loader {
            position: relative;
            margin: 0px auto;
            width: 100px;
        }
        #loader:before {
            content: '';
            display: block;
            padding-top: 100%;
        }
        #circular {
            -webkit-animation: rotate 2s linear infinite;
            animation: rotate 2s linear infinite;
            height: 100%;
            -webkit-transform-origin: center center;
            transform-origin: center center;
            width: 100%;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
        }
        .path {
            stroke-dasharray: 1,200;
            stroke-dashoffset: 0;
            -webkit-animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
            animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
            stroke-linecap: round;
        }
        .path-2 {
            stroke-dasharray: 1,200;
            stroke-dashoffset: 0;
            -webkit-animation: dash 3s ease-in-out infinite, color 8s ease-in-out infinite;
            animation: dash 3s ease-in-out infinite, color 8s ease-in-out infinite;
            stroke-linecap: round;
        }
        .path-3 {
            stroke-dasharray: 1,200;
            stroke-dashoffset: 0;
            -webkit-animation: dash 4.5s ease-in-out infinite, color 12s ease-in-out infinite;
            animation: dash 4.5s ease-in-out infinite, color 12s ease-in-out infinite;
            stroke-linecap: round;
        }
        @-webkit-keyframes rotate {
            100% {
                -webkit-transform: rotate(360deg);
                transform: rotate(360deg);
            }
        }
        @keyframes rotate {
            100% {
                -webkit-transform: rotate(360deg);
                transform: rotate(360deg);
            }
        }
        @-webkit-keyframes dash {
            0% {
                stroke-dasharray: 1,200;
                stroke-dashoffset: 0;
            }
            50% {
                stroke-dasharray: 89,200;
                stroke-dashoffset: -35px;
            }
            100% {
                stroke-dasharray: 89,200;
                stroke-dashoffset: -124px;
            }
        }
        @keyframes dash {
            0% {
                stroke-dasharray: 1,200;
                stroke-dashoffset: 0;
            }
            50% {
                stroke-dasharray: 89,200;
                stroke-dashoffset: -35px;
            }
            100% {
                stroke-dasharray: 89,200;
                stroke-dashoffset: -124px;
            }
        }
        @-webkit-keyframes color {
            100%, 0% {
                stroke: #d62d20;
            }
            40% {
                stroke: #0007e7;
            }
            66% {
                stroke: #0f0;
            }
            80%, 90% {
                stroke: #ffa700;
            }
        }
        @keyframes color {
            100%, 0% {
                stroke: #d62d20;
            }
            40% {
                stroke: #0007e7;
            }
            66% {
                stroke: #0f0;
            }
            80%, 90% {
                stroke: #ffa700;
            }
        }
    </style>
    <div id="showbox">
        <div id="loader">
            <svg id="circular" viewBox="25 25 50 50">
                <circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"/>
                <circle class="path-2" cx="50" cy="50" r="15" fill="none" stroke-width="2" stroke-miterlimit="10"/>
                <circle class="path-3" cx="50" cy="50" r="10" fill="none" stroke-width="2" stroke-miterlimit="10"/>
            </svg>
        </div>
    </div>
</div>

This displays the spinner as expected but the jquery to remove it from the dom doesn’t seem to be working… the element is still there.

Any idea why that would happen?

When I use the webdeb:app-loader package it works fine but I can’t replicate it myself…

hmm… does this template frame every single view/route in your app?

What happens if they are enter on another template/route? No loading effects?