erp
erp

Reputation: 3014

Refresh a ng-repeat list from server every x seconds

As the title suggests I want to be able to refresh a ng-repeat list from the server every 30 seconds or so. More data can be added on the backend, so I want my list to reflect that. Right now I have the regular $http.get( ) working fine which is here:

$scope.select = function() {
  $scope.searchText = '';
  $scope.selectedItem = null;
  var url = 'http:xxxxxxxxxxxx.com';
  url += $scope.selectModel.name;
  console.debug("GOING TO: " + url);
  $http.get(url).success(function(data2) {
    $scope.records = [];
    data2.forEach(function(r) {
        $scope.records.push(r);
    });
  });
};

and the portion of the web page it supplies is:

<div style="margin: 1em">
<h4>Search</h4>
        <div role="form">
            <!-- start dropdown -->
            <div class="form-group">
                <select class="form-control" ng-options="model as model.name for model in allModels" ng-model="selectModel" ng-change="select()">
                    <option value="">Choose Model</option>
                </select>
            </div>
            <!-- /end dropdown-->
            <div class="form-group">
                <input id="start_date" type="text" class="form-control" placeholder="Threat Date">
            </div>
        </div>
    <div>
        <table class="table table-hover table-striped" ng-show="records">
            <thead>
                <th>#</th>
                <th>Name</th>
                <th>Score</th>
            </thead>
            <tr data-ng-repeat=" item in records | orderBy : '-score' | limitTo : 10 " ng-click="moreInfo(item)">
                <td>{{$index+1}}</td>
                <td>{{item.name.slice(5)}}</td>
                <td>{{item.score.toFixed(3)}}</td>
            </tr>
        </table>
    </div>
</div>

Is there a way to choose a time @ which the list will refresh? And it has to be without hitting a refresh button or something like that. Thanks in advance.

EDIT This is the error I get when I try and use $interval as suggested:

ReferenceError: $interval is not defined
    at Scope.$scope.select (http:xxxxxxxxxx.com/UserQuery/js/script.js:24:7)
    at fn (eval at <anonymous> (https://code.angularjs.org/1.4.0-rc.0/angular.js:12822:15), <anonymous>:2:209)
    at Scope.$get.Scope.$eval (https://code.angularjs.org/1.4.0-rc.0/angular.js:15465:28)
    at https://code.angularjs.org/1.4.0-rc.0/angular.js:21825:13
    at https://code.angularjs.org/1.4.0-rc.0/angular.js:24485:9
    at forEach (https://code.angularjs.org/1.4.0-rc.0/angular.js:332:20)
    at NgModelController.$$writeModelToScope (https://code.angularjs.org/1.4.0-rc.0/angular.js:24483:5)
    at writeToModelIfNeeded (https://code.angularjs.org/1.4.0-rc.0/angular.js:24476:14)
    at https://code.angularjs.org/1.4.0-rc.0/angular.js:24470:9
    at validationDone (https://code.angularjs.org/1.4.0-rc.0/angular.js:24398:9)

SOLUTION With combined efforts from this and another question, I came to a solution. First off, like many on this question mentioned, the key here is the use of $interval. There are a few important things to not about using it though.

Upvotes: 1

Views: 2933

Answers (4)

Jonathan Smith
Jonathan Smith

Reputation: 2599

Try this: Ok, I think the plan is each time select is fired, the existing interval needs to be cancelled and another one started. Have a look at this:

   var intervalObj;
   $scope.select = function() {
      if (intervalObj !== null) {
          $interval.cancel(intervalObj);
          intervalObj = null;
      }
      $scope.searchText = '';
      $scope.selectedItem = null;
      var url = 'http:xxxxxxxxxxxx.com';
      url += $scope.selectModel.name;
      console.debug("GOING TO: " + url);
      $http.get(url).success(function(data2) {
        $scope.records = [];
        data2.forEach(function(r) {
            $scope.records.push(r);
        });
      });
      intervalObj = $interval(function() {
        $http.get(url).success(function(data2) {
        $scope.records = [];
        data2.forEach(function(r) {
            $scope.records.push(r);
        });
      });
    }, 30000);
};

I have not been able to fully test this, but the principle is sound.

Upvotes: 0

Mark Pieszak - Trilon.io
Mark Pieszak - Trilon.io

Reputation: 66971

Just use a $interval() around your $http to make it refresh every 30 seconds.

$interval(function () {
    $http({ 
        /* run your AJAX and update your $scope / etc */ 
    });
}, 30000); // in milliseconds

Note: $interval must be dependency injected into your controller / service / etc to work!

 // for examples sake
.controller('MyController', ['$interval', function ($interval) { }]);

Upvotes: 2

Jonathan Smith
Jonathan Smith

Reputation: 2599

Have a look at this:

https://docs.angularjs.org/api/ng/service/$interval

It wraps JavaScript's native setInterval function. You can set it to do the poll every 30 seconds.

It also returns a promise so you can cancel the interval when required.

However, please bear this in mind:

"Intervals created by this service must be explicitly destroyed when you are finished with them. In particular they are not automatically destroyed when a controller's scope or a directive's element are destroyed. You should take this into consideration and make sure to always cancel the interval at the appropriate moment. See the example below for more details on how and when to do this."

EDIT

Taking your code:

$scope.select = function() {
  $scope.searchText = '';
  $scope.selectedItem = null;
  var url = 'http:xxxxxxxxxxxx.com';
  url += $scope.selectModel.name;
  console.debug("GOING TO: " + url);
  $http.get(url).success(function(data2) {
    $scope.records = [];
    data2.forEach(function(r) {
        $scope.records.push(r);
    });
  });
};

Try changing to this:

    $scope.select = function() {
      $scope.searchText = '';
      $scope.selectedItem = null;
      var url = 'http:xxxxxxxxxxxx.com';
      url += $scope.selectModel.name;
      console.debug("GOING TO: " + url);
      $http.get(url).success(function(data2) {
        $scope.records = [];
        data2.forEach(function(r) {
            $scope.records.push(r);
        });
      });
      $interval(function() {
        $http.get(url).success(function(data2) {
        $scope.records = [];
        data2.forEach(function(r) {
            $scope.records.push(r);
        });
      });
    }, 30000);
};

If that works you can then refactor the actual $http.get out into a named function to remove the code smell.

Upvotes: 4

Ritt
Ritt

Reputation: 3349

Use ng-table instead. Have a look http://bazalt-cms.com/ng-table/

And u can call its reload propery, which will refresh your table,

The reload you can call inside $timeout service provided by angular.

$timeout(function(){
tablename.reload();
},3000);

or

Just call the select function inside the timeout

$timeout(function(){
$scope.select();
},3000);

Upvotes: 0

Related Questions