2014-08-29 13 views
7

Jestem całkiem nowy w Angular, więc może pytam o niemożliwe, ale w każdym razie, oto moje wyzwanie.Rozwiązanie do przesyłania strumieniowego JSON za pomocą oboe.js w AngularJS?

Ponieważ nasz serwer nie może paginować danych JSON, chciałbym przesłać strumień JSON i dodać go strona po stronie do modelu kontrolera. Użytkownik nie musi czekać na załadowanie całego strumienia, dlatego odświeżam widok każdego rekordu X (stronicowania).

Znalazłem oboe.js do analizy strumienia JSON i dodałem go za pomocą altanki do mojego projektu. (altanka instaluje obój - zapisz).

Chcę zaktualizować model kontrolerów podczas przesyłania strumieniowego. Nie użyłem implementacji pomas z $ q, ponieważ istnieje tylko jeden .resolve (...) i chcę, aby wiele stron danych było ładowanych przez strumień, więc $ digest musi zostać wywołane z każdą stroną. Relaksującego usługa, która nazywa się/usługa/zadania/search

I stworzył fabrykę z funkcji wyszukiwania, które ja nazywam od wewnątrz kontrolera:

'use strict'; 

angular.module('myStreamingApp') 
    .factory('Stream', function() { 
     return { 
      search: function(schema, scope) { 
       var loaded = 0; 
       var pagesize = 100; 
       // JSON streaming parser oboe.js 
       oboe({ 
        url: '/service/' + schema + '/search' 
       }) 
         // process every node which has a schema 
         .node('{schema}', function(rec) { 
          // push the record to the model data 
          scope.data.push(rec); 
          loaded++; 
          // if there is another page received then refresh the view 
          if (loaded % pagesize === 0) { 
           scope.$digest(); 
          } 
         }) 
         .fail(function(err) { 
          console.log('streaming error' + err.thrown ? (err.thrown.message):''); 
         }) 
         .done(function() { 
          scope.$digest(); 
         }); 
      } 
     }; 
    }); 

Mój kontroler:

'use strict'; 
angular.module('myStreamingApp') 
    .controller('MyCtrl', function($scope, Stream) { 
     $scope.data = []; 
     Stream.search('tasks', $scope); 
    }); 

To wszystko szwy do pracy. Po chwili jednak system działa wolno i połączenie http nie kończy się po odświeżeniu przeglądarki. Również przeglądarka (chrome) ulega awarii, gdy załadowanych jest zbyt wiele rekordów. Być może jestem na niewłaściwym torze, ponieważ przekazanie zakresu do funkcji wyszukiwania fabrycznego nie "czuje" się dobrze i podejrzewam, że wywołanie $ digest na tym zakresie sprawia mi kłopoty. Wszelkie pomysły na ten temat są mile widziane. Zwłaszcza jeśli masz pomysł na wdrożenie go gdzie fabryka (lub usługa) może powrócić obietnicę i mogę użyć

$scope.data = Stream.search('tasks'); 

w kontrolerze.

Odpowiedz

14

Wykopałem trochę dalej i wymyśliłem następujące rozwiązanie. To może pomóc komuś:

Fabryka (o nazwie Strumień) ma funkcję wyszukiwania, która jest przekazywana parametry dla żądania Ajax i funkcji wywołania zwrotnego. Wywołanie jest wywoływane dla każdej strony danych ładowanych przez strumień. Funkcja wywołania zwrotnego jest wywoływana przez funkcję odroczenia.promise, więc zakres może być aktualizowany automatycznie na każdej stronie. Aby uzyskać dostęp do funkcji wyszukiwania, używam usługi (o nazwie Search), która początkowo zwraca pustą aranżację danych. W miarę postępu strumienia fabryka wywołuje funkcję zwrotną przekazywaną przez usługę, a strona jest dodawana do danych.

Mogę teraz wywołać formularz usługi wyszukiwania w kontrolerze i przypisać wartość zwracaną do tablicy danych zakresu.

Obsługa i fabryczne:

'use strict'; 
angular.module('myStreamingApp') 
     .service('Search', function(Stream) { 
      return function(params) { 
       // initialize the data 
       var data = []; 
       // add the data page by page using a stream 
       Stream.search(params, function(page) { 
        // a page of records is received. 
        // add each record to the data 
        _.each(page, function(record) { 
         data.push(record); 
        }); 
       }); 
       return data; 
      }; 
     }) 
     .factory('Stream', function($q) { 
      return { 
       // the search function calls the oboe module to get the JSON data in a stream 
       search: function(params, callback) { 
        // the defer will be resolved immediately 
        var defer = $q.defer(); 
        var promise = defer.promise; 
        // counter for the received records 
        var counter = 0; 
        // I use an arbitrary page size. 
        var pagesize = 100; 
        // initialize the page of records 
        var page = []; 
        // call the oboe unction to start the stream 
        oboe({ 
         url: '/api/' + params.schema + '/search', 
         method: 'GET' 
        }) 
          // once the stream starts we can resolve the defer. 
          .start(function() { 
           defer.resolve(); 
          }) 
          // for every node containing an _id 
          .node('{_id}', function(node) { 
           // we push the node to the page 
           page.push(node); 
           counter++; 
           // if the pagesize is reached return the page using the promise 
           if (counter % pagesize === 0) { 
            promise.then(callback(page)); 
            // initialize the page 
            page = []; 
           } 
          }) 
          .done(function() { 
           // when the stream is done make surethe last page of nodes is returned 
           promise.then(callback(page)); 
          }); 
        return promise; 
       } 
      }; 
     }); 

Teraz mogę zadzwonić do serwisu z poziomu sterownika i przypisać odpowiedź, że obsługa w zakresie:

$scope.mydata = Search({schema: 'tasks'}); 

Aktualizacja 30 sierpnia 2014

Stworzyłem moduł obojowo-obójowy o powyższym rozwiązaniu nieco bardziej uporządkowanym. https://github.com/RonB/angular-oboe

Powiązane problemy