Search code examples
javascriptangularjspolling

Dynamically add to a list in angular


Goal: a dynamically generated list from external source.

I've set up a simple angular app that gets a list of events from an external JSON source. I want the list to update when events are added from the external source. It's currently working, but I have one problem and three questions:

1) I'm currently rewriting the list every 15 seconds. How do I just add to the end of the list without rewriting the list? (problem and question)

2) Is there another, better way to keep up to date with the external list? I'm trying to follow "RESTful" techniques, does that mean I should rely on the client side code to poll every so many seconds the way I'm doing? (best practice question)

3) Is setting the timeout in the controller best practice? Because it's controlling the action on the page?(best practice/comprehension question)

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

eventModule.controller('eventControlller', 
  function($scope, $timeout, eventList) {
    $scope.events = eventList.getAllEvents().success(
      function(events) {$scope.events = events});
    var poll = function() {
      $timeout(function() {
        $scope.events = eventList.getAllEvents().success(
        function(events) {$scope.events = events});
        poll();
      }, 15000);
    };     
  poll();
});

eventModule.factory('eventList', function($http) {
  var url = "http://localhost/d8/events/request";
    return {
      getAllEvents: function() {
    return $http.get(url);
    }
  };
});

Solution

    1. If the list is an array, and you want to add new members to it, there are a few different ways. One way is to use the prototype.concat() function, like so:

      function(events) {
          $scope.events = $scope.events.concat(events)
      });
      

      If you cannot use that then you can go for loops solution:

      function concatenateEvents(events) {
          events.forEach(function(element) {
              events.push(element);
          }
      }
      
    2. Regarding the best ways to update the list, it depends on your requirements. If 15 seconds is not too long for you, then you can keep this logic, but if you need to speed up the response time, or even make it real time, then you need to emulate server-push architecture, which is different than the default web architecture, which is request-response architecture. Basically you may want to explore web sockets, and/or long polling, or reverse ajax, or comet... has many names. Web sockets is the recommended solution, others are only in case you have to use some non-compatible browsers.

    3. Regarding the third question, I honestly don't know. Truly it doesn't feel good to control the UI from within your controller, but as I don't really know what your app is supposed to be doing, I don't know whether this is actually a bad way to do it.

    Hope this helps!

    EDIT - forgot to add another important point: You don't need to assign the eventList.getAllEvents() to $scope.events, as you are doing that in the callback handler function.

    Perhaps you can modify your controller to something like this:

    eventModule.controller('eventControlller', function($scope, $timeout, eventList) {
    eventList.getAllEvents().success(
      function(events) {
          $scope.events = events
      });
    var poll = function() {
      $timeout(function() {
        eventList.getAllEvents().success(
        function(events) {$scope.events = events});
        poll();
      }, 15000);
    };     
    poll();
    });