Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spin icon freezes while loading records

I am trying to load records using breeze. While loading record i am showing spin icon. But somehow spin icon seems to stop while records are being loaded in grid. Here is my html

<div id="showSpin" data-bind="visible: isSpinning" style="padding: 10px; position: absolute; top:248px;left: 320px;  background-color: #FFF; opacity: 0.9; filter: alpha(opacity=90);">
    <img src="/images/spin.gif" />
</div>

here is my code to load image

isSpinning(true)
context.getData(name, records).then(function (data) {
     isSpinning(false);

    setTimeout(function () {
        isSpinning(false);
    }, 300);

})
.fail("Record not found");

Update1 I tried below code as per answer but nothing happens. I also included css. But cant see anything.

<div id="loading" data-bind="visible: isSpinning" style="padding: 10px; position: absolute; top:240px;left: 280px;  background-color: #FFF; opacity: 0.9; filter: alpha(opacity=90);">
    <i class="icon-spin " style="width: 40px"></i>
    <!--<img src="../../../../../Content/images/download.jpg" style="width: 40px" />-->
</div> 
like image 884
James Avatar asked Jul 09 '14 14:07

James


3 Answers

This is happening because a Gif requires the thread to be open to display the next image. If you were using a pure css approach you would not see this issue. Take font-awesome for example -

<i class="icon-spin icon-spinner"></i>

Because this is a pure CSS approach the spinner will continue to spin even when the thread bogs down loading all of of your new records and associating their related entities.

If you need to continue spinning I would highly including this bit of CSS from the Font-Awesome source -

@-moz-keyframes spin {
  0% {
    -moz-transform: rotate(0deg); }

  100% {
    -moz-transform: rotate(359deg); } }

@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg); }

  100% {
    -webkit-transform: rotate(359deg); } }

@-o-keyframes spin {
  0% {
    -o-transform: rotate(0deg); }

  100% {
    -o-transform: rotate(359deg); } }

@-ms-keyframes spin {
  0% {
    -ms-transform: rotate(0deg); }

  100% {
    -ms-transform: rotate(359deg); } }

@keyframes spin {
  0% {
    transform: rotate(0deg); }

  100% {
    transform: rotate(359deg); } }

.icon-spin {
  display: inline-block;
  -moz-animation: spin 2s infinite linear;
  -o-animation: spin 2s infinite linear;
  -webkit-animation: spin 2s infinite linear;
  animation: spin 2s infinite linear; }

And using either a static icon, image or sprite and just applying class of 'icon-spin' to it, regardless of whether it is an icon or not.

Edit

Add this wherever you are declaring your CSS -

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">

Change this -

<div id="showSpin" data-bind="visible: isSpinning" style="padding: 10px; position: absolute; top:248px;left: 320px;  background-color: #FFF; opacity: 0.9; filter: alpha(opacity=90);">
    <img src="/images/spin.gif" />
</div>

to this -

<div id="showSpin" data-bind="visible: isSpinning" style="padding: 10px; position: absolute; top:248px;left: 320px;  background-color: #FFF; opacity: 0.9; filter: alpha(opacity=90);">
    <i class="fa fa-spinner fa-spin"></i>
</div>

The reason it is fa instead of icon is the current version of FontAwesome changed to use fa instead of icon due to collisions

Last Edit

Your problem now is that your logic is faulty. I have tried to explain this in comments but I will give one last update with EXACTLY how your logic should look if you want to show your spinner and have it spinning.

isSpinning(true)
context.getData(name, records).then(function (data) {
    isLoading(false);

    setTimeout(function () {
        isSpinning(false);
    }, 1000);

})
.fail("Record not found");


<div id="showSpin" data-bind="visible: isSpinning" style="padding: 10px; position: absolute; top:248px;left: 320px;  background-color: #FFF; opacity: 0.9; filter: alpha(opacity=90);">
    <!-- THERE IS NO REASON TO USE A VISIBLE BINDING HERE AND ON THE PARENT -->
    <i class="fa fa-2x fa-spinner fa-spin"></i>
</div>

The reason this wasn't working is in your logic. Copy this EXACTLY to your solution and it will work.

like image 81
PW Kad Avatar answered Nov 20 '22 04:11

PW Kad


This is only something of a guess, but I think your record loading script is blocking the web browser by running in the main thread. This is not a desirable behaviour but fortunately this is exactly what webworkers were made for. First I recommend you read this page to get a little background then read on.

Basically you need to first move your loading code into a separate javascript file. This separate file should contain all the code to load the record, then place it in an object and post the object back to the main thread as shown bellow. You can then invoke this code from your main thread using:

var myWorker = new Worker("my_loading_code.js");

Now the content which a webworker can directly access is limited due to thread safety concerns, therefore you may need to retrieve the records and then send them to the main thread using a postMessage(x); call which allows you to send any object back to the main page. The main page can then react to this message by installing a message handler with:

myWorker.onmessage = function(record){
    // This is only pseudo code, use your actual code here
    reactToRecievingRecord(record);
}; 

This means that the main thread is not blocked while all the records load and can animate your icon, only blocking briefly when it receives a record.

If this is not clear enough or you need more help please just ask :)

EDIT:

To go into detail, in your case, inside the separate file you will want some code which does something along the lines of:

context.getData(name, records).then(function (data) {
    postMessage(data);
})

then in your main file you want:

isSpinning(true);
var myWorker = new Worker("my_loading_code.js");
myWorker.onmessage = function(record){
    // This is only pseudo code, use your actual code here
    isLoading(false);
    isSpinning(false);
}; 

Note, this code does not actually do anything with the data once it receives it, you will want to handle that but I am sure you get the rough idea. Note these are also snippets only, you will need to turn them into full functions etc

like image 34
Vality Avatar answered Nov 20 '22 05:11

Vality


You could also Base64 encode the graphic and apply this loading graphic via CSS thus making subsequent usage faster and saving HTTP requests. The result of doing the Base64 encoded animated loader, is that for small common reusable assets like a loading or processing assets, it is already available and will continue to animate while performing numerous AJAX / HTTP requests, which is what you are trying to solve here.

See Also:

  • Is embedding background image data into CSS as Base64 good or bad practice?

  • http://css-tricks.com/data-uris/

In this way, you can have the graphic loaded when the CSS is loaded. Because having Base64 encoded images in not exactly the most maintainable solution you could use a technology like SASS / Compass and use the path to an asset and then when you pre-process or compile to css it uses the path to the asset or resource and encodes it to a Base64 encoded version for you. This technique will work with all kinds of image formats etc..

Sass / Compass Base64 References:

  • http://www.alwaystwisted.com/post.php?s=2013-11-23-sass-and-base64-images
  • http://compass-style.org/reference/compass/helpers/inline-data/

"Embeds the contents of an image directly inside your stylesheet, eliminating the need for another HTTP request. For small images, this can be a performance benefit at the cost of a larger generated CSS file"

But beware! Base64 encoding it isn't without some caveats

  • hard to maintain and update: without some tool to help, manually editing and putting together image sprites is quite a chore

  • increased memory consumption (possibly very dramatic): this is often overlooked. The time to deliver the images is decreased at the expense of a bigger memory and CPU footprint, especially for large sprites and sprites with a lot of whitespace.

  • bleedthrough: for sprites that don’t have much whitespace to separate images, there’s an increased chance of nearby images visibly bleeding through other elements, as in this case where bleedthrough was only seen on iOS (but looked fine on Chrome and Safari on the desktop). Note

Example Base64 Loading Spinner:

.genericLoader { background-image: url('data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==');   
}

Working Example:

  • http://jsbin.com/muyacodu/1/edit?html,css,output

When to Base64 Encode Images (and When Not To) - http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to/

Encoding Tools

  • http://webcodertools.com/imagetobase64converter
  • http://www.base64encode.org/
  • http://www.opinionatedgeek.com/dotnet/tools/base64encode/

Other StackOverflow References:

  • Is embedding background image data into CSS as Base64 good or bad practice?
  • base64 encoded animated gif as css background?
like image 1
Frankie Loscavio Avatar answered Nov 20 '22 04:11

Frankie Loscavio