10.6.: Loading animation / spinner?

15,189 views
Skip to first unread message

Matthias Andrasch

unread,
Mar 14, 2012, 6:16:06 PM3/14/12
to ang...@googlegroups.com
Hey,

quick question:

Has somebody implemented a solution for showing a loading/spinning animation while an ajax request (for a certain area) is loaded? Where could I attach this? 

Best regards,
Matthias

Witold Szczerba

unread,
Mar 14, 2012, 6:45:36 PM3/14/12
to ang...@googlegroups.com
Hi,
I have done it in my application. There was a discussion about this
some time ago, I have provided my solution:

https://groups.google.com/d/msg/angular/1mJDBBr0dug/05a4LJLTB4oJ

There is also a simpler method (have not checked that yet), using
ng-cloak directive, but you would have to find yourself how does the
ng-clock affect the class of element and adapt the CSS rules
accordingly.

On 14 March 2012 23:16, Matthias Andrasch

> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/angular/-/qsV7XvP_EAoJ.
> To post to this group, send email to ang...@googlegroups.com.
> To unsubscribe from this group, send email to
> angular+u...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/angular?hl=en.

Matthias Andrasch

unread,
Mar 15, 2012, 11:10:28 AM3/15/12
to ang...@googlegroups.com
Thanks Witold! I will look into this.


On Wednesday, March 14, 2012 11:45:36 PM UTC+1, Witold Szczerba wrote:
Hi,
I have done it in my application. There was a discussion about this
some time ago, I have provided my solution:

https://groups.google.com/d/msg/angular/1mJDBBr0dug/05a4LJLTB4oJ

There is also a simpler method (have not checked that yet), using
ng-cloak directive, but you would have to find yourself how does the
ng-clock affect the class of element and adapt the CSS rules
accordingly.

On 14 March 2012 23:16, Matthias Andrasch

<matthias.andrasch@googlemail.com> wrote:
> Hey,
>
> quick question:
>
> Has somebody implemented a solution for showing a loading/spinning animation
> while an ajax request (for a certain area) is loaded? Where could I attach
> this?
>
> Best regards,
> Matthias
>
> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/angular/-/qsV7XvP_EAoJ.
> To post to this group, send email to ang...@googlegroups.com.
> To unsubscribe from this group, send email to

> angular+unsubscribe@googlegroups.com.


> For more options, visit this group at
> http://groups.google.com/group/angular?hl=en.


On Wednesday, March 14, 2012 11:45:36 PM UTC+1, Witold Szczerba wrote:
Hi,
I have done it in my application. There was a discussion about this
some time ago, I have provided my solution:

https://groups.google.com/d/msg/angular/1mJDBBr0dug/05a4LJLTB4oJ

There is also a simpler method (have not checked that yet), using
ng-cloak directive, but you would have to find yourself how does the
ng-clock affect the class of element and adapt the CSS rules
accordingly.

On 14 March 2012 23:16, Matthias Andrasch

<matthias.andrasch@googlemail.com> wrote:
> Hey,
>
> quick question:
>
> Has somebody implemented a solution for showing a loading/spinning animation
> while an ajax request (for a certain area) is loaded? Where could I attach
> this?
>
> Best regards,
> Matthias
>
> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/angular/-/qsV7XvP_EAoJ.
> To post to this group, send email to ang...@googlegroups.com.
> To unsubscribe from this group, send email to

> angular+unsubscribe@googlegroups.com.

Matthias Andrasch

unread,
Apr 19, 2012, 4:53:14 AM4/19/12
to ang...@googlegroups.com
Okay I tried ng:cloak but it seems only to make sense if you're using it for the whole angular loading process, not for partials.

Example: Loading a list of users with ng:repeat via Resource/Ajax

Has somebody a method for this?  Would be really useful.

Thanks in advance! 

Peter Bacon Darwin

unread,
Apr 19, 2012, 5:40:55 AM4/19/12
to ang...@googlegroups.com
ng-cloak is only really for the situation where angular has not yet initialized and compiled up the html. In the case of partials loading then this is not an issue as angular is up and running.
How about using ng-show="loaded" on an element that wraps the partial, with $scope.loaded = false, then when the ajax call succeeds you set $scope.loaded = true and the partial becomes visible?
Pete

To view this discussion on the web visit https://groups.google.com/d/msg/angular/-/D_U0KS34P4MJ.

To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.

Alex Figueiredo

unread,
Apr 19, 2012, 11:30:58 AM4/19/12
to ang...@googlegroups.com
Hi,

I was trying to do something similiar, using ng-include.
I'm using a single ng-include directive to load multiple partials.

Here's what I'm doing:

<div ng-include src="url" onload="onLoad()" ng-show="loaded"></div> 

<button ng-click="loadTemplate(test1.htm)">Load 1</button> 
<button ng-click="loadTemplate(test2.htm)">Load 2</button>

And at my Controller I have something like:

$scope.loaded false;
$scope.url '';

$scope.loadTemplate function(url{
    $scope.url base_url(url// base_url() is a global
}

$scope.onLoad function({
    $scope.loaded true;
} 

That doesn't work, since onLoad gets called only once.
If I set loaded to true at loadTemplate, the previous loaded partial is shown until the next partial is loaded.

Any workaround for that?

Peter Bacon Darwin

unread,
Apr 19, 2012, 11:54:02 AM4/19/12
to ang...@googlegroups.com

I would update the scope.loaded when the data arrives. I.e. In the success callback

...from my mobile.

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To view this discussion on the web visit https://groups.google.com/d/msg/angular/-/KI4xHe7Uq4kJ.

Alex Figueiredo

unread,
Apr 19, 2012, 1:35:40 PM4/19/12
to ang...@googlegroups.com
I'm sorry, does ng-include have another callback besides the onLoad ?
To unsubscribe from this group, send email to angular+unsubscribe@googlegroups.com.

Johan

unread,
Apr 19, 2012, 4:38:17 PM4/19/12
to ang...@googlegroups.com
I setup 2 event handlers in root scope and then fire the events as required in the xhr/resource callback:

$scope.$on('spinnerStart', function(){ 
  $spinner.addClass('active');
});

$scope.$on('spinnerStop', function(){
 $spinner.addClass('active');
}); 

where $spinner is a the spinner element created in the base template

Johan

unread,
Apr 19, 2012, 4:39:42 PM4/19/12
to ang...@googlegroups.com
Sorry spinnerStop shoule be $spinner.removeClass('active')

zdam

unread,
Apr 19, 2012, 6:29:07 PM4/19/12
to ang...@googlegroups.com
Hi,

I used a responseInterceptor and a function added to the transformRequest pipeline to add and remove my spinner.  This means it is hooked into absolutely all $http calls without any other code in any other parts of your system.

This is for rc5, I think for 10.6 the interceptors and requests might not be arrays so you will have to simply assign rather than push, but make sure to also call the original function inside your own.

Cheers, Adam.

angular.module('SharedServices', [])
    .config(function ($httpProvider) {
        $httpProvider.responseInterceptors.push('myHttpInterceptor');
        var spinnerFunction = function (data, headersGetter) {
            // todo start the spinner here
            return data;
        };
        $httpProvider.defaults.transformRequest.push(spinnerFunction);
    })
// register the interceptor as a service, intercepts ALL angular ajax http calls
    .factory('myHttpInterceptor', function ($q, $window) {
        return function (promise) {
            return promise.then(function (response) {
                // do something on success
                // todo hide the spinner

            }, function (response) {
                // do something on error
                // todo hide the spinner
                return $q.reject(response);
            });
        };
    })

Peter Bacon Darwin

unread,
Apr 19, 2012, 6:36:39 PM4/19/12
to ang...@googlegroups.com
Very slick idea.  Nice one, Adam!

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To view this discussion on the web visit https://groups.google.com/d/msg/angular/-/AfpLQP-8V1MJ.

To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.

Nolan Dubeau

unread,
Apr 19, 2012, 7:33:19 PM4/19/12
to ang...@googlegroups.com, ang...@googlegroups.com
This looks great, but is hard for us new to AngularJS to grasp.   Would you be able to put it into a fiddle so we can see it in action? Thanks!

Cheers,

Nolan Dubeau

Sent from my Commodore-64
Load *.*,8,1
--

Johan

unread,
Apr 19, 2012, 10:44:57 PM4/19/12
to ang...@googlegroups.com
@zadam +1 on your solution - nice!

ThomasBurleson

unread,
Apr 20, 2012, 12:49:47 PM4/20/12
to ang...@googlegroups.com
@zadam +1 - nice!

zdam

unread,
Apr 20, 2012, 6:26:56 PM4/20/12
to ang...@googlegroups.com
Hi, here is an example fiddle:  http://jsfiddle.net/zdam/dBR2r/ 

What I did was:
1. Click 'Edit Me' on the  Wire up a Backend example on the AngularJS site http://angularjs.org to get that code in a fiddle.
2. Copy/pasted the above code into the fiddle directly into the top of the javascript
3. Added window.alert(...) where I had placed //todo comments (pretend the alerts are the spinner being shown/hidden)
4. Fixed a bug - I had to add the line of code: return response;  (line 18 of the javascript)
5. Add the SharedServices dependency to the project module.  see this line:     angular.module('project'['mongolab''SharedServices']). 

Hope that helps, Adam.
To unsubscribe from this group, send email to angular+unsubscribe@googlegroups.com.

Nikolaos Dimopoulos

unread,
Apr 20, 2012, 8:28:04 PM4/20/12
to ang...@googlegroups.com
Thank you Adam!

Awesome solution!

Johan

unread,
Apr 23, 2012, 10:23:48 PM4/23/12
to ang...@googlegroups.com
@zdam - is there a way to conditionally show spinner based on request? I have a application heartbeat GET request and cannot see an easy way to stop this from periodically showing the spinner. I can see data for POST in function(data, headersGetter){...} but nothing for GET.

Suggestions?

Thanks

I posted this question earlier but did not seem to make it into the thread - if it did please excuse doubling up!


On Friday, April 20, 2012 10:29:07 AM UTC+12, zdam wrote:

zdam

unread,
Apr 23, 2012, 10:35:13 PM4/23/12
to ang...@googlegroups.com
Hi,

We are a bit stuck because we don't really have enough information in our transformRequest function.

Ideally I'd like to see a more symmetrical pre/post http api that provides all information to us.

A workaround: You could add a custom header to your heartbeat request, and then in in the transformRequest function, use the headersGetter to see if your custom header exists, in which case you do not show the spinner.

Cheers, Adam.

zdam

unread,
Apr 23, 2012, 10:36:27 PM4/23/12
to ang...@googlegroups.com
Hi,

We are a bit stuck because we don't really have enough information in our transformRequest function.

Ideally I'd like to see a more symmetrical pre/post http api that provides all information to us.

A workaround: You could add a custom header to your heartbeat request, and then in in the transformRequest function, use the headersGetter to see if your custom header exists, in which case you do not show the spinner.

Cheers, Adam.

On Tuesday, 24 April 2012 12:23:48 UTC+10, Johan wrote:

Johan

unread,
Apr 24, 2012, 5:48:44 AM4/24/12
to ang...@googlegroups.com
Adam - thanks, did not think of adding the header, that could/should work. Agree be nice to be able to add/see more information in the request transform.

Krzysztof Danielewicz

unread,
May 27, 2012, 3:21:15 PM5/27/12
to ang...@googlegroups.com
Is there a way to inject "$rootScope" to module.config and using it in transformRequest handler? 

what I'd like to do is following
angular.module('RequestResponseNotifier', [])
    .config(function ($httpProvider) {
        $httpProvider.responseInterceptors.push('myHttpInterceptor');
        var spinnerFunction = function (data, headersGetter) {
            // todo start the spinner here
 
 
            var scope = angular.injector(['ng']).get('$rootScope'),
                headers = headersGetter(),
                isResourceRequest = headers['Content-Type'] === "application/json";
            
            if (isResourceRequest && scope) {
 
                console.log('start spinner');
                scope.$broadcast('loadingDataStart');
            }
 
            return data;
        };
        $httpProvider.defaults.transformRequest.push(spinnerFunction);
    })
// register the interceptor as a service, intercepts ALL angular ajax http calls
    .factory('myHttpInterceptor'function ($q, $window, $rootScope) {
        return function (promise) {
            return promise.then(function (response) {
                // do something on success
                // todo hide the spinner
                var headers = response.headers(),
                    isNotResourceResponse = headers['content-type'] !== "application/json; charset=utf-8";
                if (isNotResourceResponse) {
                    return response;
                }
                console.log('stop spinner');
                $rootScope.$broadcast('loadingDataEnd');
                return response;
 
            }, function (response) {
                // do something on error
                // todo hide the spinner
                var headers = response.headers(),
                    isNotResourceResponse = headers['content-type'] !== "application/json; charset=utf-8";
                if (isNotResourceResponse) {
                    return response;
                }
                $rootScope.$broadcast('loadingDataEnd');
                console.log('stop spinner');
                return $q.reject(response);
            });
        };
    });

however, the loadingDataStart event is not propagated to the rootscope.

thanks, for any help

Krzysztof Danielewicz

unread,
May 27, 2012, 5:27:15 PM5/27/12
to ang...@googlegroups.com
finally I've found $http.pendingRequest, it enables my to monitor pending requests and display alert.

Please do not remove this property from Api because I've notice that the property is for debugging purpose

angular.module('ResourceLoadingNotification', [])
    .directive('resourceLoadingNotification'function factory($http) {
        var directiveDefinitionObject = {
            template:
        '<div class="row">' +
            '<div class="offset4 span4" >' +
                '<div class="alert" ng-hide="isLoadingAlertHidden()">' +
                        '<strong >Proszę czekać. Następuję odczytywanie danych.</strong>' +
                '</div>' +
            '</div>' +
        '</div>',
            replace: true,
            restrict: 'E',
            link: function postLink(scope, iElement, iAttrs) {
                scope.isLoadingAlertHidden = function () {
                    return $http.pendingRequests.length === 0;
                };
                scope.$watch(scope.isLoadingAlertHidden, function (parameters) {
                    console.log("isLoadingAlertHidden" + scope.isLoadingAlertHidden());
                });
 
 
            }
        };
        return directiveDefinitionObject;
    });

Tomarto

unread,
Oct 31, 2012, 9:54:24 AM10/31/12
to ang...@googlegroups.com
Hey Krzysztof, this works great! I just have a little problem here. I defined some directives that are using services to perform ajaxRequest and it is not monitoring this requests. Do you have any idea why this is happening?

Thanks!

Krzysztof Danielewicz

unread,
Nov 1, 2012, 7:17:41 AM11/1/12
to ang...@googlegroups.com
As far as I know, it can only track the ajax request within the angular scope application. The others can be handled by additional custom code. 

Krzysztof

James Morgan

unread,
Dec 21, 2012, 7:26:53 AM12/21/12
to ang...@googlegroups.com

I too am also trying to implement a very similar feature to this, I noticed that your final solution doesnt use this interceptor pattern but used directives instead, did you ever find out why the "loadingDataStart event is not propagated to the rootscope."?

I have exactly the same problem, my loadingDataStart  is never propergated.

I dont want to use a directive as I feel like this event driven approach suit my application better, is there another alternative or a way of getting this to work?

Many thanks?

lucassus

unread,
Jan 14, 2013, 5:15:07 AM1/14/13
to ang...@googlegroups.com

Olivier Clément

unread,
Jan 14, 2013, 1:11:16 PM1/14/13
to ang...@googlegroups.com
Hi Lucassus,
just fumbled on your post while looking for similar solution as an example;

Do you have any example on how this would be used/implemented?
And would you mind if I would reuse your code in a project I'm working on (not open source, at work)

Thanks

Łukasz Bandzarewicz

unread,
Jan 14, 2013, 1:16:47 PM1/14/13
to ang...@googlegroups.com
Of course you could reuse my code, it's open source ;)


It's simpler and cleaner. Instead manually tracking of pending request I use $http.pendingRequests property.


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
 
 



--
Pozdrawiam,
Łukasz Bandzarewicz

Olivier Clément

unread,
Jan 14, 2013, 1:21:02 PM1/14/13
to ang...@googlegroups.com, lukasz.ba...@gmail.com
That looks great, thanks!
Will check this out when I get there (still working on bunch of other stuff at the same time ;))
Also, I prefer to ask just in case, especially considering this project is not opensource or anything

Anyways, thanks!

Tony Polinelli

unread,
Jan 15, 2013, 1:37:52 AM1/15/13
to ang...@googlegroups.com


Did i miss some complexity here?  You are just trying to show a loading spinner right? -- doesnt this work (replace loading... with a spinner image)



Dave Merrill

unread,
Jan 15, 2013, 10:38:41 AM1/15/13
to ang...@googlegroups.com, to...@touchmypixel.com
Click Load 1 after opening, or the same button twice in a row, and the loading indicator never closes.

Dave

Olivier Clément

unread,
Jan 15, 2013, 10:42:45 AM1/15/13
to ang...@googlegroups.com, to...@touchmypixel.com
At some point, the idea of it (at least in my view) is to have a module/factory that will create a loading anim/text whenever you need it, wherever you need. Interceptor pattern will probably be of used in there.

I'm not sure yet if Lucas' code is up for that (haven't put a lot of thoughts into this yet) but it looks like a good starting point


On Tuesday, January 15, 2013 1:37:52 AM UTC-5, Tony Polinelli wrote:

S Aden

unread,
Feb 9, 2013, 1:51:22 PM2/9/13
to ang...@googlegroups.com, luca...@gmail.com
Brilliant! Exactly what I needed. Thank you so much.
Message has been deleted

Andy Joslin

unread,
Feb 9, 2013, 4:31:54 PM2/9/13
to ang...@googlegroups.com
Aye, as Olivier said it would be great to have some sort of factory which would let me place a loading spinner globally (eg, big spinner over a large area with text and a backdrop to gray things out) or on an individual element. And I'd like to specify on every $http request which spinner it would for.

So I just decided to make it.. here's a little over an hour of plunkering: http://plnkr.co/edit/a4szsJIqj0d9dVi92TJe?p=preview
There's a nice demo there.

It allows you to link multiple http requests to one http request tracker.  So you do

```
$rootScope.myTracker = promiseTracker('myTracker');

$http.get('myThing', { tracker: 'myTracker' });
$http.get('myThing2', { tracker: 'myTracker' });

<div ng-show="myTracker.active()">
  Loading... This will show if any requests marked 'tracker1' are waiting for a response
</div>
```

I also went as far as to add error, success, start and done events for the trackers.  So when any request specified as 'myTracker' starts, finishes, or specifically has success/error, you can catch an event and do something.

This is really nice  because I can have one loading spinner in a particular area of my app depending on just the requests I want to have it.

You can also add any old promise to the request tracker:
promiseTracker('myTracker').add(myPromise);

And it will work like the http requests too.

Adil Wali

unread,
Mar 5, 2013, 10:02:08 PM3/5/13
to ang...@googlegroups.com
Andy: I LOVE this approach.  I'm trying to implement it into our app now, but I'm having a little trouble with passing the 'tracker' config variable into $http.  Our app is using the $ngResource wrapper for almost everything.  

Upon peeking at the ngResource code, I didn't see an easy way to actually pass 'tracker: 'myTracker'' into $http.  Would love some advice on how we might implement this sweet promiseTracker, given our approach.

Is anyone else using $ngResource?  If so, what are you doing to add a loading animation? 

Thanks,
AW

Andy Joslin

unread,
Mar 5, 2013, 10:08:03 PM3/5/13
to ang...@googlegroups.com
Hi Adil! 

Luckily, you don't have to use $http; that's just a shortcut.

With the version at https://github.com/ajoslin/angular-promise-tracker you can just do:

var myTracker = promiseTracker('myTracker');
var promise = myResource.get();
myTracker.addPromise(promise, 'value_to_pass_to_myTracker.on("start")');

Adil Wali

unread,
Mar 6, 2013, 8:37:43 PM3/6/13
to ang...@googlegroups.com
Andy: Brilliant!  That method works swimmingly!  

As an errant thought to others that are thinking heavily about good UX:  One thing we've noticed is that our cool loading animation flashes in-and-out very quickly for people on a high-speed internet connection (assuming the server isn't bogged down.)  As such, it would be snazzy to have some kind of 'minimum_display_time' variable.  This way, the animation displays for just enough time to be recognized and understood by the user, but not so much time that the site appears to be loading data when it isn't.  (Though this will technically be the case for some number of milliseconds, of course.) 

Anyway, just a cool wishlist idea/feature.  Once we push our next rev, I may actually have enough time to figure out an elegant way to do it myself.   Look out for a pull request :)  

--AW
Reply all
Reply to author
Forward
0 new messages