$ionicLoading indicator flashing and closing "too early" / state change

I am authenticating against a Firebase. While checking the user credentials I want to show a loading indicator. On successful authentication I redirect the user to a certain state and then want the loading indicator to stop.

I have two problems:

  1. Sometimes the loading indicator shows for a split second, then goes away. After a moment it comes back and hides again. It is only called once. I cannot really reproduce this one reliably.
  2. There is a delay between the point when the loading indicator closes and when the desired state is rendered. Is there a way to hide the loading indicator only once a desired state is fully rendered?

What I have:

(I put the loading indicator in a service. I tried putting it directly in the controller which had the same result. So this shouldnā€™t be a problem.)

Loading Indicator Service

.factory('BusyService', ['$ionicLoading', function($ionicLoading) {
  var busy = null;

  return {

    show: function() {
      busy = $ionicLoading.show({
        content: '<h1><i class="icon ion-ios7-reloading"></i></h1>',
        animation: 'fade-in',
        showBackdrop: true,
        maxWidth: 93,
        showDelay: 0
      });
    },

    hide: function() {
      busy.hide();
    }

  };

}]);

Login method inside Authentication Service

login: function(email, password) {
        var deferred = $q.defer();

        assertAuth();

        simpleAuth.$login('password', {
          email: email,
          password: password,
          rememberMe: true
        })
        .then(function(user) {
          setToken(user.firebaseAuthToken);
          deferred.resolve(user);
        }, function(error) {
          deferred.reject(error);
        });

        return deferred.promise;
      }

Login method inside controller

$scope.login = function() {
        BusyService.show();

        AuthService.login($scope.authForm.email, $scope.authForm.password)
          .then(function() {
            $state.go('home');
          }, function() {
            $scope.authForm.error = MESSAGES.LOGIN_FAILED;
          })
          .finally(function() {
            BusyService.hide();
          });
      }
    };

Any help is greatly appreciated. Thanks in advance.

hi,
set to your showDelay a value greater than or equal 100,
this should solve your problem :wink:

1 Like

Thanks for your hint. It works way better now.

Could you explain why this works? From the docs and the code in ionic.js this option should only affect showing the loading indicator, not hiding it?

Side question: Is there any way to start the loading indicator in one state and stop it when another state has been fully rendered?

I cheat by using a ā€œmain controllerā€ that wraps my whole app. This isnā€™t considered best practice though.

Then, each state or view controller can use the methods in them main controllerā€™s scope. I put the $ionicLoading.show method in the main controller. So, the sub controller calls it there.

    // Triggered on a button click, or some other target
    $scope.showLoadingIndicator =  function(msg, closeAfter) {

        $scope.loadingIndicator = $ionicLoading.show({
            content: msg,
            animation: 'fade-in',
            showBackdrop: false,
            maxWidth: 200,
            showDelay: 100
        });

        if(closeAfter && parseInt(closeAfter, 10)) {

            $timeout( function() {
                $scope.loadingIndicator.hide();
            }, parseInt(closeAfter, 10));
        }

    };


    $scope.hideLoadingIndicator =  function() {

        if( $scope.loadingIndicator) $scope.loadingIndicator.hide();

    };

Then, when the transition to a new state is complete, you can call the hide method in that stateā€™s controller.

$scope.hideLoadingIndicator();

A more proper way of doing this would be to use a service and set a property in the service to equal the $ionicLoading.

Warning : Untested and rough sample code for your controller


LoaderFactory.saveLoading( $ionicLoading.show({
            content: msg,
            animation: 'fade-in',
            showBackdrop: false,
            maxWidth: 200,
            showDelay: 100
        });
);