Own all-the-time loader

I want to display some simple page-loader to the end user each and every time they click some link, some button, some menu item, does anything that causes URL to be changed and new page to be loaded (soon).

Maybe not that “simple” since this loader must include iframe and an animated .svg file inside.

What is the best approach to this in Yii 2 Advanced app?

I know how to make a loader. I know that I can use either some already existing library or write my own loader in jQuery or even plain HTML, CSS and Javascript.

What I don’t know is how to correctly register such solution within Yii 2 application, so all the required frontend files (.css, .js, .html) are correctly published and that such loader-like solution works aways. Meaning that no matter what user does, click etc. whenever we are waiting for the new page to be loaded from sever, we always see this or that loader.

This is kind of strange question.
What’t the purpose of this loader? Is it supposed to just fill the time of waiting with some fancy animation? Or is there supposed to be some information in the loading and the new page is loaded after the user read the information?

You mentioned some strange stuff

  • loader must include iframe: Why? If you wanna show some svg animation, there is absolutely no need to use iframe. Iframe is very specific thing to use in very rare situations.
  • I don’t know is how to correctly register such solution within Yii 2 application: you don’t ask how to put js/css into the page, do you? Because it’s one of the basic things in Yii - Assets - Application Structure: Assets | The Definitive Guide to Yii 2.0 | Yii PHP Framework It’s just a matter of very few lines. But you have must used that before, that’s why I don’t think you’re asking about this.

If you think about what happens when the user click somewhere, what actions are done (browser sends request, waits for the first response, server is rendering the page, start sending data, browser starts showing data, it takes some time, page jumpes …), there is a reason nobody bothers users with some loading animations. Because the time from click to fully loaded consists from different things and putting a loading animation right after the click is only one small part of loading a new page (until the first response).

Maybe you can have some nice loadings when you have so called one site app, where you actually don’t jump from one url to other but make the request under the hood via ajax and only change the url also via JS (Yii2 actually can that with Pjax), but you would have to use some robust JS solution like React or other I guess.

Many years ago I actually did something you’re talking about on my old blog (not for mobile) https://alterego.ondrejvasicek.cz/ and it was some pretty nasty stuff to deal with :slight_smile: My goal was that use thinks it’s actually one page app, even though it’s not. So I had to do some magic, covers, transitions, animations and extreme optimalizations to achieve the effect, that after click, user see loading, there is no flash of white “between-page” and right away other page is loaded. And it has work fluently even if the background is changing. It looks quite cool actually, mainly when you listing the articles left-right by clicking on the arrows on the sides, but I wouldn’t do that again. Looking back, it was like hacking something which wasn’t supposed to do that.

But maybe your question was about something completely different and my answer is useless :smiley:

Hi,

Thanks for trying to help and providing a lot of information. I should rather start from the end:

This is exactly what I am looking for and asking for. The “no white between-page” says all about my question.

The only difference between your solution and the business requirement given to me by my customer is that you did not register your spinner / loader to all the events (see below for details). Meaning that when you press “back” in browser then there is no loader and there still is a “white between-page”.

You have probably registered your loader to a click even, not to URL change event.

Maybe using “loader” word is misleading. Maybe “spinner” or “gear” would be better?

The first sentence of you is straight to the point. The application is designed from elderly people, some of them are with sight problems or even partial blindness. And the requirement is that “small spinner that replaces favicon when on browser tab when page loads is not enough”.

User:

  1. Must have a clear huge animation that clearly shows that next page is being loaded
  2. Must not be able to click another link or button when page loads (thus spinner must cover entire screen with some kind of overlay).

I know how to register JS/CSS assets within the page. I don’t know how to register “global on click” or “global on load” event. So no matter what triggered new page to be loaded – spinner appears.

I know how to display SVG (or regular) image without iframe. I don’t know how to animate SVG without iframe. The original page (form where my customer took this requirements) uses iframe just for that purpose only (to animate gear-like SVG animation). Hence the question. If animating (actually: rotating) SVG objects is possible without iframe then iframe is not needed.

I have made such solution 15+ years ago, in a pure (then) HTML4. The idea is that spinner / loader appears in a matter of miliseconds after you click some button or link (or trigger request in any other way), but stays on screen until another page is loaded.

I know that full request processing is a long, multi-stage process. But the business assumption / requirement here is that user must see some kind of spinner or loader in between seeing current and the new content. When the new content is received from server, the spinner can be long gone (and will be long gone, since it is a part of the previous page). That is not a problem. Given the fact that this particular application is using a very slow connection and a server, time between clicking a link or button and receiving some content in response can be even 3-5 seconds.

We need spinner to “cover the time when nothing happens”, if I may say so. When user sees current page and waits for the response from click (request) to arrive. Does this make more sens to you?

Having SPA (Single Page Application) is the exact thing that I don’t want to have! :slight_smile: I am as far from this or even its look & feel) as possible. All I want to do is to show “no white page-between requests”.

You answer seems as useful as it can be! :slight_smile:

Ok, so we established the problem, let’s look for the solution.

… you did not register your spinner / loader to all the events (see below for details). Meaning that when you press “back” in browser then there is no loader and there still is a “white between-page”.
You have probably registered your loader to a click even, not to URL change event.

Yep, it’s only registered on specific clicks, but add it to pressing back would be just a matter of few characters of js code. Like really few. But you can only see this when you simulate very slow connection in you browser setting.
But in general that’s the problem with this solution - on different PC it can behave differently and maybe on slower PC little white flash can appear. The solutions just tries to minimize the “white flash” to minimum, but you can be never sure how the browser behaves. If there can’t be any white flash at all, the OPA/Ajax is the only solution, because it has no redirects. You can’t really control how browser handles loading the new page. You can only tune it a bit.

The solution from the blog has 3 parts

  1. Show spinner when moving to other page (it’s registered on specific links) - pure jQUery - moving, fading actual content and showing spinner. Waiting for the browser to redirect to new page
  2. This was the nasty part - when browser jumps to a new page, the new background and spinner MUST show right away. No delay. To achieve this, it wasn’t possible to just show some normal page which makes usual requests to JS files, css files or waiting for some code on the bottom of the page. So for this reason, if you look to the code, there is very slim head with non blocking loading of JS files via head.js library (it was great that time) and right after the opening body element there is this code
<div id="pozadi" style="position: fixed;top: 0; background: url('/img/body-pozadi2.png') fixed; min-height: 100%; height: 100%; width: 100%; opacity: 0.5; z-index: 2;"></div>

Css in the HTML, which is bad practice but it’s super fast and the browser displays it right after the previous page is gone.
3) Then the real page is loaded with opacity 0 and fade in or otherwise else animated in when loading is finished.

So you could actually use this approach - just have to bring in bigger spinner :slight_smile:

I know how to register JS/CSS assets within the page. I don’t know how to register “global on click” or “global on load” event. So no matter what triggered new page to be loaded – spinner appears.

Here it’s important to say one thing - your question actually isn’t Yii related at all. It’s pure JS/CSS thing. Yii doesn’t care about those thing - which is good.

I know how to display SVG (or regular) image without iframe. I don’t know how to animate SVG without iframe. The original page (form where my customer took this requirements) uses iframe just for that purpose only (to animate gear-like SVG animation). Hence the question. If animating (actually: rotating) SVG objects is possible without iframe then iframe is not needed.

Ok, you can officially forget about iframe. Iframe is absolutely different technology, it has absolutely (like really) nothing to do with svg or animations. If you want animate something, you do it via css or JS (css is better). Putting svg to iframe doesn’t make the svg spin.
The reason why it was like that on the old site is (I guess) fact, that on the iframe page, there was the whole combo - svg and css for animation. So the page only loaded iframe where was the svg alerady spinning. Which is just silly solution. So - no more iframe.

So what you should/can do, if you can’t/don’t want to use SPA.

You can use the solution from the blog

  1. Register spinner overly to some actions (clicks, back button, …), wait for browser to load new page
  2. On new page mage sure you show the overlay spinner again as soon as possible - it must be the first thing on the page in pure HTML
  3. When the rest of the page (set to opacity 0) is loaded, animate it to opacity 1 and hide the spinner overlay.

Done.

Or you can use the Yii Pjax, which is again - pure html/css/js component, it’s not even a part of Yii3 because of that. Pjax helps you avoid the reloading of new pages entirely, because it can make all the clicks be ajax calling. It can even modify your url without reloading the page. It really can look like SPA, but it’s not, it’s just simple ajax.
Then you only need to only catch the moment when the pjax starts and ends and show/hide you overlay. This shouldn’t be so difficult, but you will have to look to the docs (GitHub - yiisoft/jquery-pjax: pushState + ajax = pjax and Pjax, yii\widgets\Pjax | API Documentation for Yii 2.0 | Yii PHP Framework) and use Events I guess.
Great thing with pjax is, that you don’t actually have to refresh the whole page, but only some part, but your overlay can still cover the whole page. So it can be somehow hybrid and looks really a lot like SPA.

But no matter if you chose first, second or totally different solution - it’s a matter of html/js/css - no Yii needed here.

Thank you for a great answer again. I’ll try to keep this short this time:

That is what I am asking for. I know that the actual code will be pure frontend (jQuery or pure JavaScript). Which doesn’t change the fact that I still can embed (publish / register) it within the code of my Yii 2 application. I simply forgot how to do this. And where? Should I register this JS code with head section of my theme file? Or maybe some view? I am not sure.

Depends on what application you are designing and were it is deployed. Try to enroll some really slow (cheapest) virtual server in AWS in South America or Japan region, deploy your Yii 2 app there and try to access it from Europe (over half of the world) and you will certainly see your spinner on nearly every click or request.

I don’t understand why you are keep saying this. It is a pure Yii question. It doesn’t matter that it is based on CSS or JS in implementation. As long as you are operating on views (which are HTML and are using CSS and JS), as long as you are using or want to use yii\web\AssetBundle or yii\web\AssetManager then this is a pure Yii question.

Everything what was said here can be narrowed down to three points:

  1. How and were (in layout?) to put your example HTML code? Where to register its publication?
  2. How to show it up every time in every view URL changes (no matter, if by click, Back button press etc.) – what would be the minimalistic JS code to achieve this?
  3. How to use AssetBundle or AssetManager to put both points above together, register everything and make sure that it is available (and shown) in every view and in every scenario?

I know that I am asking for a ready solution. But I have virtually zero experience with AssetBundle and AssetManager, so I don’t even know where to start solving this myself. Sorry.

Sorry for the late reply, I lost and forgot the page when moving to new OS.
Detecting back button - you should detect every possible attempt to change the url. I’m not JS guy, but there will be a lot of examples online.
Registering JS code - if you do it using Yii, you can do it anywhere in view. That’s the beauty. You pass a param to the register method, where you want to have the JS code rendered (head, bigin, end, ready, load), no matter where is registered - Displaying Data: Working with Client Scripts | The Definitive Guide to Yii 2.0 | Yii PHP Framework

I don’t understand why you are keep saying this. It is a pure Yii question. It doesn’t matter that it is based on CSS or JS in implementation. As long as you are operating on views (which are HTML and are using CSS and JS), as long as you are using or want to use yii\web\AssetBundle or yii\web\AssetManager then this is a pure Yii question.

It’s like saying, that changing a flat tire or choosing best dashcam to the car is “pure specific BMW question”, because you own BMW. No, tires and dashcams are products of it’s own (the same the JS code you’re seeking for) and can be part of every car manufacturer (like the JS can be part of every website). It doesn’t matter what car you have, the dashcams and tires works the same (let’s keep it simple). The same here with the JS code - you want to know specific JS code. This JS code doesn’t care what’s the PHP framework behind it. It’ll work every where, even without Yii, even with different language than PHP, it will even work in pure HTML/JS site.
So no, your question isn’t related to Yii. Everybody with JS/HTML knowledge can help you and any code can be put into Yii site.
The way how you attach the JS code to the web is Yii related, but the JS code itself not.

Everything what was said here can be narrowed down to three points:

  1. How and were (in layout?) to put your example HTML code? Where to register its publication?
  2. How to show it up every time in every view URL changes (no matter, if by click, Back button press etc.) – what would be the minimalistic JS code to achieve this?
  3. How to use AssetBundle or AssetManager to put both points above together, register everything and make sure that it is available (and shown) in every view and in every scenario?
  1. The HTML will be hidden be default, so just put it before the end of the body. In the main layout. So it will be a part of every page.
  2. Not a JS guy, have to google it. Don’t search for Yii :slight_smile: It will be something like detecting url change.
  3. You don’t register HTML into HTML. See the 1)
    Talking about registering the JS - Displaying Data: Working with Client Scripts | The Definitive Guide to Yii 2.0 | Yii PHP Framework - when you wanna put JS code to some specific view.
    If you wanna have some JS code available in every request, use AssetBundle - Application Structure: Assets | The Definitive Guide to Yii 2.0 | Yii PHP Framework
    Or if you don’t wanna mess up with that, just use pure HTML and put the code to the head element
 <script src="script.js"></script> 

It’ll do the work perfectly. Asset Bundles has their reasons when you dynamically combine them and call them on different places. I guess it’s not your case so you don’t have to use them.

Thanks for a bunch of a really interesting and professional thoughts. I will surely consider each of them in details, but not before I actually sit down to implementation of this feature. And due to its nature (not really mission-critical element of an app), it was postponed to the November or December.

Just a drop from my side. While waiting for your answer, I have came across AmagiLoader.

A very cool feature of it is that it generates everything (both content in HTML and magic in JS) on-the-fly. You don’t have to register anything. All you have to do is given in the below example:

<html>
<head></head>
<script src="amagiloader.js"></script>
<body>
    <button onclick="AmagiLoader.show()">AmagiLoader.show()</button>
</body>
</html>

Of course, one must bind AmagiLoader.show() to other events, like for example browser history modification (URL change detection), you’ve mentioned. Or even page refresh event.