web-dev-qa-db-fra.com

AngularJS: affiche le chargement du HTML jusqu'à ce que les données soient chargées

Comment puis-je demander à AngularJS d'afficher un spinner de chargement jusqu'à ce que le chargement des données soit terminé?

Si mon contrôleur a $scope.items = [{name: "One"}] configuré statiquement, et un chargeur AJAX qui remplit $scope.items[0]['lateLoader'] = "Hello", J'aimerais que le spinner s'affiche jusqu'à ce que la charge AJAX soit terminée, puis remplit la plage liée avec les données récupérées.

<ul ng-repeat="item in items">
  <li>
    <p>Always present: {{item.name}}</p>
    <p>Loads later: <span ng-bind="item.lateLoader"><i class="icon icon-refresh icon-spin"></i></span></p>
  </li>
</ul>

Ce code remplit immédiatement la plage liée et comme item.lateLoader est vide, le spinner est remplacé par rien.

Comment dois-je procéder proprement?

21
JP.

Je créerais une directive personnalisée selon l'autre réponse, mais voici comment vous pouvez le faire sans la directive, ce qui pourrait être une bonne idée d'apprendre avant d'entrer dans des fonctionnalités plus complexes. Quelques choses à noter:

  1. Utilisation d'un setTimeout pour simuler un appel ajax
  2. L'icône de chargement est préchargée et est masquée lors du chargement des données. Juste une simple directive ng-hide.
  3. Il n'y a pas d'image de chargement dans mon exemple juste du texte qui est caché (évidemment votre html aura les bonnes références css).

Démo: http://plnkr.co/edit/4XZJqnIpie0ucMNN6egy?p=preview

Vue:

<ul >
  <li ng-repeat="item in items">
    <p>Always present: {{item.name}}</p>
    <p>Loads later: {{item.lateLoader}} <i ng-hide="item.lateLoader"  class="icon icon-refresh icon-spin">loading image i don't have</i></p>
  </li>
</ul>

Manette:

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  $scope.items = [{name: "One"}];
  setTimeout(function() {
    $scope.$apply(function() {
     $scope.items[0].lateLoader = 'i just loaded';  
    });
  }, 1000);
});
24
lucuma

En fait, j'utilise une solution pour cela depuis un certain temps maintenant, qui fonctionne très bien et qui vaut mieux que d'utiliser un délai d'attente à mon avis. J'utilise $ resource, mais vous pourriez faire la même chose avec $ http. Sur mes objets de ressources $, j'ajoute le bit dans le code suivant qui définit chargé à true.

$scope.customer = $resource(dataUrl + "/Course/Social/" + courseName)
    .get({}, function (data) { data.loaded = true; });

Ensuite, à mon avis, je peux utiliser:

ng-hide="customer.loaded"

Bien sûr, je n'utiliserais pas une ressource $ directement dans un contrôleur, je l'extrait vers un service customerRepository, mais c'était plus simple de le montrer ici.

20
Jim Cooper

Je créerais une directive personnalisée et mettrais un balisage par défaut avec spinner.

Voici quelques liens sur les directives personnalisées

1) Les vidéos Egghead sont géniales! http://www.egghead.io/video/xoIHkM4KpHM

2) Documents officiels Angular on directives http://docs.angularjs.org/guide/directive

3) Bon aperçu de angular en 60 minutes) http://weblogs.asp.net/dwahlin/archive/2013/04/12/video-tutorial-angularjs-fundamentals- in-60-ish-minutes.aspx

5
vittore

@lucuma,

Excellente réponse, une alternative peut être d'injecter $ timeout et de remplacer la fonction native timeout:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, $timeout) {

        $scope.name = 'World';
        $scope.items = [{name: "One"}];
        $timeout(function() {
                $scope.$apply(function() {
                        $scope.items[0].lateLoader = 'i just loaded';  
                });
        }, 1000);
});
0
C. S.