2013-04-23 10 views
21

W jaki sposób mam AngularJS wyświetlać spinner do momentu załadowania danych?AngularJS: wyświetlaj ładowanie kodu HTML do momentu wczytania danych.

Jeśli mój kontroler ma $scope.items = [{name: "One"}] skonfigurowany statycznie i program ładujący AJAX, który zapełnia $scope.items[0]['lateLoader'] = "Hello", chciałbym, aby spinner wyświetlał się aż do zakończenia ładowania AJAX, a następnie zapełnił związany zakres z pobranymi danymi.

<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> 

Ten kod zapełnia związany rozpiętość od razu, a jak item.lateLoader jest pusty przędzarka otrzymuje z niczym.

Jak powinienem to zrobić w sposób czysty?

+0

dlaczego nie statycznie ładować obrazu ładowacza w znacznikach? – vittore

Odpowiedz

23

Chciałbym stworzyć dyrektywę niestandardowe jak na innej odpowiedzi, ale tutaj jest to, jak można zrobić bez dyrektywy, co może być dobrym pomysłem, aby się uczyć przed wejściem do bardziej złożonej funkcjonalności. Kilka rzeczy do zapamiętania:

  1. Korzystanie z funkcji setTimeout do symulacji połączenia ajax
  2. Ikona ładowania jest wstępnie załadowana i jest ukrywana podczas ładowania danych. Prosta dyrektywa ng-hide.
  3. W moim przykładzie nie ma obrazu ładującego, tylko tekst, który się ukrywa (oczywiście twój html będzie miał poprawne referencje css).

Demo: http://plnkr.co/edit/4XZJqnIpie0ucMNN6egy?p=preview

Widok:

<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> 

Kontroler:

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

Utworzę niestandardową dyrektywę i wstawię domyślny znacznik za pomocą pokrętła.

Oto kilka linków na własnych dyrektyw

1) egghead filmy są niesamowite! http://www.egghead.io/video/xoIHkM4KpHM

2) oficjalne kątowe Docs na dyrektywach http://docs.angularjs.org/guide/directive

3) Dobra przegląd kątowe w 60ish minut http://weblogs.asp.net/dwahlin/archive/2013/04/12/video-tutorial-angularjs-fundamentals-in-60-ish-minutes.aspx

+1

Zgadzam się z tym, mimo że mógł on również zrobić 'ng-show' lub' ng-hide' na podstawie danych, czy istnieje (nieokreślony) – lucuma

+0

@lucuma Tak, ale wydaje się, że jest to dobre miejsce do wielokrotnego użytku w nim jest własna dyrektywa. – vittore

+0

Jestem całkiem nowy w Angular - jeśli masz przykład lub link do dokumentacji, która byłaby naprawdę pomocna, mimo że jestem szczęśliwy, że sam pójdę po dokumentację myśliwską! –

0

@lucuma,

Świetna odpowiedź, alternatywą może być wstrzykiwać $ limit czasu i zamień macierzysty timeout functio n:

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

Funkcja setTimeout została właśnie użyta do symulacji oczekiwania, chociaż masz rację, lepiej byłoby skorzystać z opcji $ timeout. – lucuma

+4

Limit czasu $ jest przydatny, ponieważ zawija wywołanie zwrotne do $ apply automatycznie. To znaczy. możesz usunąć '$ scope. $ apply (function() {' ze swojego przykładu: –

19

I rzeczywiście zostały przy użyciu rozwiązanie tego problemu na chwilę się, że działa świetnie i jest lepsza niż limit czasu moim zdaniem. Używam $ resource, ale możesz zrobić to samo z $ http. W moich obiektach $ resource dodajemy bit w poniższym kodzie, który ustawia załadowany na true.

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

Wtedy, moim zdaniem może używać:

ng-hide="customer.loaded" 

Oczywiście, nie będę używać $ zasobu bezpośrednio w kontrolerze, wyodrębnić, że do usługi customerRepository, ale było łatwiej pokazać to w ten sposób.

+1

To zdecydowanie najlepsze rozwiązanie. – Steven

Powiązane problemy