2014-08-29 3 views
7

Я довольно новичок в Angular, поэтому, возможно, я прошу невозможного, но в любом случае, вот мой вызов.Решение для потоковой передачи JSON с использованием oboe.js в AngularJS?

Поскольку наш сервер не может разбивать на страницы данные JSON, я хотел бы передать JSON и добавить его по страницам в модель контроллера. Пользователю не нужно дожидаться загрузки всего потока, поэтому я обновляю представление для каждой записи X (для страниц).

Я нашел oboe.js для разбора потока JSON и добавил его с помощью беседки к моему проекту. (bower install oboe --save).

Я хочу обновить модель контроллера во время потоковой передачи. Я не использовал реализацию qq pomises $ q, потому что существует только один .resolve (...), и я хочу, чтобы несколько страниц данных загружались через поток, поэтому $ digest нужно вызывать с каждой страницы. Успокоительная служба, называется это/сервис/задачи/поиск

Я создал фабрику с функцией поиска, которую я называю внутри контроллера:

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

Моего контроллер:

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

Это все швы для работы. Через некоторое время система замедляется, и http-вызов не завершается после обновления браузера. Кроме того, браузер (хром) выходит из строя, когда загружено слишком много записей. Возможно, я ошибаюсь, потому что передача области функции поиска на заводе не «правильна», и я подозреваю, что вызов $ digest в этой области дает мне проблемы. Любые идеи по этому вопросу приветствуются. Особенно, если у вас есть идея о его реализации, где завод (или услуга) может вернуть обещание, и я мог бы использовать

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

в контроллере.

ответ

14

Я выкопал немного дальше и придумал следующее решение. Это может помочь кому-то:

Завод (названный Stream) имеет функцию поиска, которая передает параметры для запроса Ajax и функцию обратного вызова. Обратный вызов вызывается для каждой страницы данных, загружаемых потоком. Функция обратного вызова вызывается с помощью отложенного.произведения, поэтому область может автоматически обновляться с каждой страницы. Для доступа к функции поиска я использую службу (с именем Search), которая первоначально возвращает пустой массив данных. По ходу потока фабрика вызывает функцию обратного вызова, переданную службой, и страница добавляется к данным.

Теперь я могу вызвать форму службы поиска в контроллере и присвоить возвращаемое значение массиву данных областей.

Сервис и завод:

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

Теперь я могу позвонить в службу внутри контроллера и назначить ответ службы в объеме:

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

Update 30 августа 2014

Я создал модуль углового гобоя с вышеупомянутым решением, немного более структурированным. https://github.com/RonB/angular-oboe

Смежные вопросы