web-dev-qa-db-fra.com

(Angular-ui-router) Affiche l'animation de chargement pendant le processus de résolution.

C'est une question en deux parties:

  1. J'utilise la propriété de résolution dans $ stateProvider.state () pour récupérer certaines données du serveur avant de charger le contrôleur. Comment pourrais-je obtenir une animation de chargement à afficher pendant ce processus?

  2. J'ai des états enfants qui utilisent également la propriété resol. Le problème est que ui-router semble vouloir finaliser tout résout avant de charger tout contrôleur . Existe-t-il un moyen de charger les contrôleurs parents une fois leurs résolutions résolues, sans avoir à attendre que toutes les résolutions enfants soient résolues? Une réponse à cette question résoudra probablement également le premier problème.

80
Matt Way

EDIT: Voici une solution encore plus simple, testée et fonctionnant bien:

Dans mon contrôleur principal, j'ai simplement

$scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
    if (toState.resolve) {
        $scope.showSpinner();
    }
});
$scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
    if (toState.resolve) {
        $scope.hideSpinner();
    }
});

Cela montre le compteur lorsque nous sommes sur le point d’aller dans un état qui a quelque chose à résoudre et le cache, lorsque le changement d’état est terminé. Vous voudrez peut-être ajouter des éléments de contrôle dans la hiérarchie des états (c’est-à-dire aussi afficher le compteur si un état parent en cours de chargement résout quelque chose), mais cette solution me convient parfaitement.

Voici mon ancienne suggestion pour référence et comme alternative:

  1. Dans votre contrôleur d’application, écoutez l’événement stateChangeStart et vérifiez si vous êtes sur le point de passer à un état dans lequel vous souhaitez afficher un compteur pendant la résolution (voir https://github.com/angular -ui/routeur-ui/wiki/référence rapide # wiki-events-1 )

    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
        if (toState.name == 'state.with.resolve') {
            $scope.showSpinner();  //this is a function you created to show the loading animation
        }
    })
    
  2. Lorsque votre contrôleur est finalement appelé, vous pouvez masquer le compteur.

    .controller('StateWithResolveCtrl', function($scope) {
        $scope.hideSpinner();
    })
    

Vous pouvez également vérifier les erreurs éventuelles lors de la résolution en écoutant le fichier $stateChangeError événement et masquer l'animation pendant que vous gérez l'erreur.

Ce n'est pas tout à fait propre car vous distribuez la logique pour le spinner entre les contrôleurs, mais c'est un moyen. J'espère que ça aide.

71
Stefan Henze

J'ai développé la solution suivante qui fonctionne parfaitement pour moi.

1. Ajoutez l'app.run suivant

app.run(function($rootScope){

    $rootScope
        .$on('$stateChangeStart', 
            function(event, toState, toParams, fromState, fromParams){ 
                $("#ui-view").html("");
                $(".page-loading").removeClass("hidden");
        });

    $rootScope
        .$on('$stateChangeSuccess',
            function(event, toState, toParams, fromState, fromParams){ 
                $(".page-loading").addClass("hidden");
        });

});

2. Placez l'indicateur de chargement juste au-dessus de la vue ui. Ajoutez id = "ui-view" au div. Ui-view.

<div class="page-loading">Loading...</div>
<div ui-view id="ui-view"></div>

. Ajoutez ce qui suit à votre css

.hidden {
  display: none !important;
  visibility: hidden !important;
}

NOTE:

A. Le code ci-dessus affichera l'indicateur de chargement dans deux cas 1) lorsque angular est chargée pour la première fois 2) lorsque la vue est changé.

B. Si vous ne voulez pas que l'indicateur soit affiché lorsque l'application angular est chargée pour la première fois (avant qu'une vue ne soit chargée), ajoutez alors hidden class à la chargement div comme ci-dessous

<div class="page-loading hidden">Loading...</div>
22
Blesson Jose

J'ai trouvé en utilisant angular-loading-bar qui fonctionnait très bien pendant de longues résolutions en raison de l'accès au réseau.

16
Brian de Alwis

Pourquoi ne pas ajouter du contenu à la div qui sera rempli par ui-router une fois les propriétés résolues?

Dans votre index.html

<div ui-view class="container">
    Loading....
</div>

L'utilisateur verra maintenant "Loading ..." pendant que les propriétés sont résolues. Une fois que tout est prêt, le contenu sera remplacé par ui-router par le contenu de vos applications.

8
Wolfgang

J'utilise un gif animé que je montre uniquement quand $http a des demandes en attente.

Dans mon modèle de page de base, j'ai une barre de navigation et un contrôleur de barre de navigation. La partie pertinente du contrôleur ressemble à ceci:

controllers.controller('NavbarCtrl', ['$scope', '$http',
    function ($scope, $http) {
        $scope.hasPendingRequests = function () {
            return $http.pendingRequests.length > 0;
        };
    }]);

Le code correspondant dans mon HTML est:

<span class="navbar-spinner" ng-show="hasPendingRequests()">
    <img src="/static/img/spinner.gif">
</span>

J'espère que ça aide!

7
joshvillbrandt

Mon idée est de parcourir le graphe d’états entre états de transition sur $stateChangeStart et rassemblez toutes les vues impliquées. Puis chaque ui-view La directive surveille si la vue correspondante est impliquée dans la transition et ajoute 'ui-resolving' classe sur son élément.

La démo plunker introduit deux états racine: first et second, ce dernier a deux sous-états second.sub1 et second.sub2. L'état second.sub2 cible également footer la vue appartenant à son grand-parent.

4
aikoven

Ceci est un chargeur pour globalement quand la page navigue entre n'importe quel état (n'importe quelle page), mettez dans app.js

.run(
    ['$rootScope',
        function($rootScope) {
            $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
                $rootScope.preloader = true;
            })
            $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
                $rootScope.preloader = false;
            })
        }
    ])

En html:

<div ng-show="preloader">Loading...</div>
3
manoz

Je préfère utiliser une directive pour correspondre à toute activité de chargement, principalement pour garder ma base de code propre

angular.module('$utilityElements', [])
.directive('loader',['$timeout','$rootScope', function($timeout, $rootScope) {
    return {
      restrict: 'A',
      template: '<div id="oneloader" class="hiddenload">loading...</div>',
      replace: true,
      compile: function (scope, element, attrs) {
        $timeout(function(){
          $rootScope
              .$on('$stateChangeStart',
                  function(event, toState, toParams, fromState, fromParams){
                      $("#oneloader").removeClass("hiddenload");
              });

          $rootScope
              .$on('$stateChangeSuccess',
                  function(event, toState, toParams, fromState, fromParams){
                      //add a little delay
                      $timeout(function(){
                        $("#oneloader").addClass("hiddenload");
                      },500)
              });
        }, 0);
      }
    }
  }]);
2
vorillaz

L'utilisation de $stateChangeStart Et des éléments similaires a depuis été déconseillée et remplacée par Transition Hooks . Donc, pour la réponse de Stefan Henze, la version mise à jour serait:

$transitions.onStart({}, function(transition) {
  if (transition.to().resolve) {
    $scope.showSpinner();
  }
});

$transitions.onSuccess({}, function(transition) {
  if (transition.to().resolve) {
    $scope.hideSpinner();
  }
});

Vous pouvez l'utiliser dans votre contrôleur parent. N'oubliez pas d'injecter $transitions -

.controller('parentController',['$transitions',function($transitions){...}]);

Aussi, gardez à l'esprit qu'un resolve qui est un objet vide restituera toujours transition.to().resolve == true, donc ne laissez pas d'espace réservé vide resolve dans la déclaration d'état.

2
IB2DEV

Mon idée d'utiliser la vue en utilisant la résolution dans le routeur ça marche génial. essaye ça.

//edit index.html file 
<ion-nav-view>
    <div ng-show="loadder" class="loddingSvg">
        <div class="svgImage"></div>
    </div>
</ion-nav-view>

// css file

.loddingSvg {
    height: 100%;
    background-color: rgba(0, 0, 0, 0.1);
    position: absolute;
    z-index: 99;
    left: 0;
    right: 0;
}

.svgImage {
    background: url(../img/default.svg) no-repeat;
    position: relative;
    z-index: 99;
    height: 65px;
    width: 65px;
    background-size: 56px;
    top: 50%;
    margin: 0 auto;
}

// edit app.js

 .run(function($ionicPush, $rootScope, $ionicPlatform) {




        $rootScope.$on('$stateChangeStart',
            function(event, toState, toParams, fromState, fromParams) {
                $rootScope.loadder = true;
            });

        $rootScope.$on('$stateChangeSuccess',
            function(event, toState, toParams, fromState, fromParams) {
                $rootScope.loadder = false;
            });

});
1

Si quelqu'un utilise ngRoute, il faut attendre resolve avant de charger la vue suivante et utiliser angular-bootstrap-ui pour ui, vous pouvez faire le suivant :

app.config([
  "$routeProvider", "$locationProvider", function($routeProvider, $locationProvider) {
    return $routeProvider.when("/seasons/:seasonId", {
      templateUrl: "season-manage.html",
      controller: "SeasonManageController",
      resolve: {
        season: [
          "$route", "$q", "$http", "$modal", function($route, $q, $http, $modal) {
            var modal, promise, seasonId;
            modal = $modal.open({
              backdrop: "static",
              template: "<div>\n  <div class=\"modal-header\">\n    <h3 class=\"modal-title\">\n      Loading...\n    </h3>\n  </div>\n  <div class=\"modal-body\">\n    <progressbar\n      class=\"progress-striped active\"\n      value=\"'100'\">\n    </progressbar>\n  </div>\n</div>",
              keyboard: false,
              size: "lg"
            });
            promise = $q.defer();
            seasonId = $route.current.params.seasonId;
            $http.get("/api/match/seasons/" + seasonId).success(function(data) {
              modal.close();
              promise.resolve(data);
            }).error(function(data) {
              modal.close();
              promise.reject(data);
            });

            return promise.promise;
          }
        ]
      }
    });
  }
]);
0
Blaskovicz