Spin icon freezes while loading records
Asked Answered
S

3

14

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> 
Sheeting answered 9/7, 2014 at 14:44 Comment(15)
I believe this is because the browser is loading a lot of records and basically freezes for a bit before showing the record. This effect might vary based on browsers. I am not sure if there is anyway around itElbertine
I tested on IE 10 , chrome and result is same. So you mean no solution for this?Sheeting
Could be your computer is slower or you are simply loading too much at once. I don't know the functions you are using, you can try jquery ajax and see if that works betterElbertine
@Elbertine My computer is very fast. Even if i load 20 records it doesnt spin. I am using breeze to load dataSheeting
I assume you already tested that the spinner actually spins by itself. I don't know about breeze, it is possible that's the cause of it. I have experienced similar behaviour with jquery but it's only sometimesElbertine
@Elbertine yes it spins. I clicked on image and checked if it was spinning. I would be thankful to you if you can give me solution. I also experience same with ajax request while trying to retrieve from WCF service. So i think its nothing to do with breezeSheeting
I don't know a solution for this, I added the js tag to your question and hopefully it will draw more attention and someone can provide a solutionElbertine
Do you not see that your set timeout has commented out the closing line? Also you are telling it after 300 milliseconds to stop spinning if you uncomment that out...Holohedral
@PWKad When i click on button then i set isSpinning variable to true and then i call service to get the data and after recieving data from service i stop spinning by setting timeout. By mistake i had commented the line but its not the actual caseSheeting
Not sure who is downvoting and why? What is wrong with my question? i have put in some efforts as wellSheeting
Please help me. I am really struggling.Sheeting
You may need to do the loading in a worker thread, its possible the loading is blocking the thread which animates the icon.Avrom
@Avrom can you tell me how. You can get bounty if you can answer itSheeting
+1 ed to counteract the downvote, this question is valid and actually quite an interesting issue, also please see my answer. and feel free to reply if it is lacking.Avrom
@Avrom many thanks for upvoting. dont know which useless had downvoted itSheeting
H
11

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.

Holohedral answered 8/8, 2014 at 15:36 Comment(22)
Let us continue this discussion in chat.Sheeting
So if the solution is working for you but you need to make adjustments I would recommend reading the font awesome docs. As it stands this should fix the problem you are having but you just need to make some adjustments to accommodate for your liking. In particular use fa-2x or fa-3x to make it larger but their docs are invaluableHolohedral
Its spinning but if i use it on button and not inside div.. why??Sheeting
sorry not working on button either. I mean it works if i just use icon on button with no hiding and unhiddingSheeting
if i remove visible binding on icon then it works <i class="fa fa-2x fa-spinner fa-spin" data-bind="visible: isLoading"></i> iconSheeting
Happy, I am trying to help you but I don't think you are trying anything right now. You obviously are setting isLoading = false as soon as your data call begins. So you are making it visible from the parent but not from the child. jsfiddle.net/pwkad/0bzg5ne0/1Holohedral
Hello i am really trying and thats why i tested if i use icon on button then it works or not. I am realy frustrated with this issueSheeting
so when should i make it visible then? I want to make visible after i click on search button. When i click search button it goes to server to fetch data via ajax request. after i recieve data i want to stop showing.Sheeting
If you see my question , thats what i am exactly doing, so dont know what your edit will solve my issue. I am exactly doing same stepsSheeting
It spins for 1 second or so and then when it goes to fetch data from server it just freezesSheeting
That's probably because you aren't using promises properly. Console.log when the promise gets returned to the getData call vs when the actual data is returned, I bet the getData call's promise is returned first.Holohedral
So is there any other way i can use promise? Where exactly to put console.log? before calling getData and after it has finished?Sheeting
@Happy The problem here is I have more than adequately answered your original question and demonstrated multiple times that the reason you are experiencing variations right now is because you have logic or syntactical issues. Your original question was around how can you prevent the gif from freezing, which I answered, then how can I use icons, which I answered, where do I put CSS, I answered, why doesn't it show when xxx, I answered, now you are asking about how to properly use q.js and JavaScript promises. Consider marking this as correct if the solution works and searching on promises.Holohedral
By the way a 300 ms timeout means your spinner is only spinning for .3 seconds, change it to 10000 for 10 seconds and you will see what I mean. If you aren't sure how to use logging statements in JavaScript consider looking up how to console.log and check timing. If you need to learn promises consider looking up a tutorial or walk-thru on promises.\Holohedral
I set 100000000 but still it freezes. Your solution doesnt solve my issue. My logic is correct but dont know exactly whats happening behind. I would really like to thank to you for being patient with me.Why dont you try yourself in your application to load lots of record using ajax and check if it works. I dont have any logic issues but i am missing something or need to add something. I cant tell you how frustrated i am . Solving this past 1 week now :(Sheeting
i read this somewhere "I have seen this behavior in the past when making AJAX calls. I believe this is related to the fact that browsers are only single threaded, so when the AJAX call is returned the thread is working on the call, so consequentially the animated GIF needs to stop momentarily."Sheeting
I have it in many of my applications and pure css animations are not affected by the browsers' single thread being held up.Holohedral
Are you aware about breeze framework? I think its something to do with that. I am using breeze framework to get data which internally uses oData and Ajax. If i use this spin.js using normal ajax request then i can see that its spinning but when i make request through breeze then it freezesSheeting
Breeze.js only does what you tell it to, the freezing is because you are returning way too much data. To get around it you asked how to prevent the icon from freezing, which I have already answered numerous times, if you have a new question related to it not freezing I would suggest starting a new question.Holohedral
I am returning 200 records, still then it freezes? Is there any other way we could handle this? Is it anything special does breeze framework require?Sheeting
Is it something you can point to me groups.google.com/forum/#!topic/durandaljs/VnSX-uV-fA8Sheeting
Note: You have to use inline styles to get this to work nicely. And here are some style changes to center it on the page: top: 50%; left: 50%; transform: translate(-50%, -50%);Tut
A
1

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

Avrom answered 8/8, 2014 at 15:8 Comment(9)
As per you example i need to move this code context.getData(name, records).then(function (data) { to some other file ??Sheeting
@Happy I am going to edit the answer as this comment box is too small to reply properly.Avrom
@Happy does that help at all? You place the first bit into a file called my_loading_code.js (once you have played around and it does what you want) and the second bit replaces what you had originally in your main file.Avrom
i have still not tried but this method i cant use it because i have to create new js file only to load ajax request. I have so many ajax request in my application and then it will too many js files only for those. Any other ideas?Sheeting
@Happy Don't worry, you dont have to create a new js file for every different ajax request. Create only a single extra js file which after being created will be sent a message by the main thread telling it what kind of request it is to handle, the worker can then run the appropriate function/code path. This means you only need a single script for the worker thread which can be used for every type of request.Avrom
As per your example i have call this "context.getData(name, records).then(function (data) {" inside new js file? am i correct?Sheeting
@Happy Yes, that is correct, but you can prefix that with a check as to which kind of request it is so you can have multiple types in the same worker file.Avrom
Are you aware about breeze framework? I think its something to do with that. I am using breeze framework to get data which internally uses oData and Ajax. If i use this spin.js using normal ajax request then i can see that its spinning but when i make request through breeze then it freezesSheeting
Is it something you can point to me groups.google.com/forum/#!topic/durandaljs/VnSX-uV-fA8Sheeting
C
1

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:

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:

"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:

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

Encoding Tools

Other StackOverflow References:

Crore answered 9/8, 2014 at 23:26 Comment(3)
i tried it but still same issue. It just freezes during ajax requestSheeting
Are you aware about breeze framework? I think its something to do with that. I am using breeze framework to get data which internally uses oData and Ajax. If i use this spin.js using normal ajax request then i can see that its spinning but when i make request through breeze then it freezesSheeting
Is it something you can point to me groups.google.com/forum/#!topic/durandaljs/VnSX-uV-fA8Sheeting

© 2022 - 2024 — McMap. All rights reserved.