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


#1

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.


#2

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


#3

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?


#4

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
        });
);