Good pattern for a loader in Angular app? - angularjs

I'm working on an AngularJS-based business app. In most common scenario before I show the view I'm loading some data by making a few $http POST calls. I want to show a loader in the meantime. So far I've done it by $broadcasting an event and catching it elsewhere with dedicated controller. This allows me to have a single loader per web page, which is fine. At least for now.
But maybe are there any better approaches?

Instead of broadcasting the events yourself you can take advantage of the start and finish events that the route provider are throwing apon view-change.
Angular router ($route)
$rootScope.$on('$routeChangeStart', function(e) {
openLoader();
});
$rootScope.$on('$routeChangeSuccess', function(e) {
closeLoader();
});
ui-router ($state)
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
openLoader();
});
$rootScope.$on('$stateChangeSuccess', function(e, toState, toParams, fromState, fromParams) {
closeLoader();
});
And you might want to add a filter here if you have states/routes where the loader should not be displayed.

The approach:
You can have a block level element in your main page containing gif loader or "Loading..." text. The visibility of this element should be hidden by default.
Inside Request Interceptor you can make the block level element visible and inside Response interceptor if all the request are completed and there are no pending requests you can hide this block level element.
You can achieve this functionality in a common place and so far have found this as a best approach

Related

Run a function every time an angular route is navigated to

I want to run a function every time an Angular route is navigated to.
One option is I just add myFunction() to the top of every controller. Seems really repetitive. Is there a better way to run myFunction() every time $location changes?
If you are using ui-router, you can simply bind a function to the $rootscope.
See the stateChange section: https://github.com/angular-ui/ui-router/wiki#state-change-events
$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){ ... })

Preventing state change of ui-router displaying back button in next state in ionic

I am using the below code to prevent the state change in ui-router.
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
event.preventDefault();
});
but again if I move to any state it displays ionic back button enable.
As per my knowledge it is adding to the ionicHistory but couldn't find any solution.
Help with the solution please.

How can I bring up an "in progress" loading bar in between ui-router state transitions?

I have an AngularJS application that uses ui-router. There are times when the application waits while moving from one state to another and while the resolves are still in progress.
Does anyone have (or have they seen) any examples of how I can present an "in-progress" loading bar on the screen just during the time of the resolve from the one state to another?
You can use the events emitted by ui-router (as well as the native routeProvider).
Plunker
Something like this:
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
$rootScope.stateIsLoading = true;
})
$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){
$rootScope.stateIsLoading = false;
})
Then in HTML:
<section ui-view ng-hide="stateIsLoading"></section>
<div class="loader" ng-show="stateIsLoading"></div>
docs
You can use resolve to provide your controller with content or data
that is custom to the state. resolve is an optional map of
dependencies which should be injected into the controller.
If any of these dependencies are promises, they will be resolved and
converted to a value before the controller is instantiated and the
$stateChangeSuccess event is fired.

Angular UI Router escaped slashes bug when go to state manually

Why Angular UI router in my simple example encode slashes in url if I mannually trigger state change (with $state.go(toState, toParams)).
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams, error) {
console.log("stateChangeStart");
$rootScope.loading = true;
if(!isLoggedIn) {
event.preventDefault();
Api.get().then(function(response){
isLoggedIn = response;
$state.go(toState, toParams);
});
}
});
Here is full example.
http://plnkr.co/1mSXJbN1PMrFiG72oa9m
For example url like: /template1 is encoded to %252Ftemplate1. Otherwise state is also encoded.
This is really weird, how i can disable that?
In $stateChangeStart event I simulate server side user authentication. Another part of this question is how i can treat url /template1 same as /template1/ in this concrete example?
P.S. I shut down html5 mode since it needs a properly configured server (for testing (bug?) in this example html5 mode is required).
Tnx

Can't get $anchorScroll working on $stateChangeSuccess?

I'm trying to adapt the answer give in this similar question How to handle anchor hash linking in AngularJS. I need to be able to use it with ui-router. I've tested anchor scrolling as a clickable function in my controller and that is working. Here is the code for that
$scope.anchor = function () {
console.log('test');
$location.hash('comments');
$anchorScroll();
};
If I try to invoke that function immediately nothing happens
$scope.anchor();
If I try to invoke it on a $stateChangeSuccess nothing happens. I threw in a log for sanity and that is firing. I also tried a trick to prevent further routing logic from kicking in. It was mentioned in the linked post but I'm not sure if it's necessary for my case.
app.run(function ($rootScope, $location, $stateParams, $anchorScroll) {
// allow anchorScrolling
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
console.log('stateChangeSuccess');
var old = $location.hash();
$location.hash('comments');
$anchorScroll();
//reset to old to keep any additional routing logic from kicking in
$location.hash(old);
});
});
I'm guessing that I'm running into race conditions or my anchor scroll is somehow triggering another route change. But I can't figure out how to track these issues down. Any thoughts?
EDIT: Update I removed the $location.hash(old); and put the rest of the $anchorScroll pieces into a timeout function and it's now working. I also added in the $stateParams.scrollTo to make this useable with query params. Any ideas as to what is causing my race condition and how this might be solved without a $timeout function?
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
console.log('stateChangeSuccess');
$timeout(function() {
$location.hash($stateParams.scrollTo);
$anchorScroll();
}, 300);
});
From $anchorScroll documentation
It also watches the $location.hash() and scrolls whenever it changes to match any anchor. This can be disabled by calling $anchorScrollProvider.disableAutoScrolling().
Try removing $location.hash(old);
If that fixes it, use $anchorScrollProvider.disableAutoScrolling() to disable it reacting to another state change.

Resources