Exploring AngularJS' usage of server polling

Currently, I am delving into AngularJS to expand my knowledge. My initial attempt at retrieving new data every second proved successful:

'use strict';

function dataCtrl($scope, $http, $timeout) {
    $scope.data = [];

    (function tick() {
        $http.get('api/changingData').success(function (data) {
            $scope.data = data;
            $timeout(tick, 1000);
        });
    })();
};

Upon trying to replicate a sluggish server by delaying the thread for 5 seconds, I noticed that it waits for the response before updating the UI and setting another timeout. However, when I refactored the code to leverage Angular modules and Dependency Injection for module creation, encountered an issue:

'use strict';

angular.module('datacat', ['dataServices']);

angular.module('dataServices', ['ngResource']).
    factory('Data', function ($resource) {
        return $resource('api/changingData', {}, {
            query: { method: 'GET', params: {}, isArray: true }
        });
    });

function dataCtrl($scope, $timeout, Data) {
    $scope.data = [];

    (function tick() {
        $scope.data = Data.query();
        $timeout(tick, 1000);
    })();
};

The revised code only functions effectively with prompt server responses. In case of any delay, it continuously sends out requests without waiting for a response, ultimately causing the UI to clear. I suspect utilizing a callback function could resolve this issue. I experimented with:

var x = Data.get({}, function () { });

However, I encountered an error: "Error: destination.push is not a function". My attempt was based on the examples provided in the $resource documentation, which I found somewhat confusing.

How can I rectify the shortcomings in my second approach?

Answer №1

Make sure to invoke the tick function within the callback of the query method.

function updateData($scope, $timeout, DataService) {
    $scope.data = [];

    (function tick() {
        $scope.data = DataService.query(function(){
            $timeout(tick, 1000);
        });
    })();
};

Answer №2

Newer versions of angular have recently introduced $interval which outperforms $timeout when it comes to server polling.

function updateData() {
    // Ensure smooth data display on screen
    DataService.query({ field: $scope.value }, function(data){
        $scope.data = data;
    });
};

var pollPromise = $interval(updateData, 1000);

// Stop polling upon page transitions
$scope.$on('$destroy', function(){
    if (angular.isDefined(pollPromise)) {
        $interval.cancel(pollPromise);
        pollPromise = undefined;
    }
});

Answer №3

My implementation involves recursive polling, waiting for the server response before initiating the next timeout. In case of errors, it continues polling in a more relaxed manner based on the duration of the error.

Check out the demo here

Learn more about this approach here

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

app.controller('MainCtrl', function($scope, $http, $timeout) {

    var loadTime = 1000,
        errorCount = 0,
        loadPromise;

    var getData = function() {
        $http.get('http://example-api.com/data')

        .then(function(res) {
             $scope.data = res.data;

              errorCount = 0;
              nextLoad();
        })

        .catch(function(res) {
             $scope.data = 'Error';
             nextLoad(++errorCount * 2 * loadTime);
        });
    };

     var cancelNextLoad = function() {
         $timeout.cancel(loadPromise);
     };

    var nextLoad = function(mill) {
        mill = mill || loadTime;

        cancelNextLoad();
        $timeout(getData, mill);
    };

    getData();

    $scope.$on('$destroy', function() {
        cancelNextLoad();
    });

    $scope.data = 'Loading...';
   });

Answer №4

To implement polling easily, one can utilize the $interval service provided by AngularJS. For detailed documentation on $interval, check out the following link:
https://docs.angularjs.org/api/ng/service/$interval
Issue: One common problem encountered when using $interval is the possibility of initiating a new request before the previous one has been completed, especially during server interactions or HTTP service calls that experience delays exceeding the specified interval time.
Solution:
1. To prevent this issue, ensure that the polling task involves fetching simple status updates from the server, such as a single bit or lightweight JSON data. It's crucial to set the interval time appropriately to avoid overlapping requests.
2. If the problem persists for any reason, consider implementing a global flag that checks whether the previous request has finished before sending another one. This approach may cause a slight delay in polling but prevents premature request transmissions.
Additionally, if there's a need to establish a threshold value after which the polling should cease, it can be achieved through the following method.
For a detailed working example and explanation, refer to this link: here

angular.module('myApp.view2', ['ngRoute'])
.controller('View2Ctrl', ['$scope', '$timeout', '$interval', '$http', function ($scope, $timeout, $interval, $http) {
    $scope.title = "Test Title";

    $scope.data = [];

    var hasvaluereturnd = true; // Flag to check 
    var thresholdvalue = 20; // interval threshold value

    function poll(interval, callback) {
        return $interval(function () {
            if (hasvaluereturnd) {  //check flag before starting a new call
                callback(hasvaluereturnd);
            }
            thresholdvalue = thresholdvalue - 1;  //Decrease threshold value 
            if (thresholdvalue == 0) {
                $scope.stopPoll(); // Stop $interval if it reaches the threshold
            }
        }, interval)
    }

    var pollpromise = poll(1000, function () {
        hasvaluereturnd = false;
        //$timeout(function () {  // You can test scenarios where the server takes more time than the interval
        $http.get('http://httpbin.org/get?timeoutKey=timeoutValue').then(
            function (data) {
                hasvaluereturnd = true;  // set Flag to true to initiate a new call
                $scope.data = data;

            },
            function (e) {
                hasvaluereturnd = true; // set Flag to true to initiate a new call
                //You can also set it to false based on your error handling requirements
            }
        );
        //}, 2000); 
    });

    // stop the interval.
    $scope.stopPoll = function () {
        $interval.cancel(pollpromise);
        thresholdvalue = 0;     //reset all flags. 
        hasvaluereturnd = true;
    }
}]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error thrown by custom draggable directive in AngularJS due to range issue

I am having trouble with a custom draggable directive in AngularJS. I keep getting a RangeError. Can someone please help me diagnose the issue in this code? (function (window, angular, undefined) { var app = angular.module('ngDraggableModule&a ...

What is the method for retrieving the name of a canceled file?

When a user clicks on the "Cancel" button during an upload, I am attempting to retrieve the filename of the file that was canceled. However, it seems like the current method I am using (var image_file_name) is not successfully retrieving the name of the ca ...

Experience the Power of Vue.js in Your Shopify Store

I have encountered an issue while attempting to integrate 3 custom modals into Shopify. Upon implementing them, I received the following error in the console (not originating from my Vue files, but rather from the Shopify template): [Vue warn]: Error comp ...

I'm looking for a solution to transfer data from Django views to a JavaScript script within a template. I'm currently working on creating a chart and need to showcase some specific information

I have a question regarding passing a variable into NEED_VARIABLE_PASSED. This block of code is located within one of my HTML templates. I am aware that I cannot directly use {{variable}}, so I am wondering if there is an alternate method to achieve this ...

What is the best way to prevent useEffect from triggering when a modal is being rendered?

I'm currently developing a react movie application. I am facing an issue with the hero picture feature that displays a random popular movie or show. Whenever I click the button to open a modal, the useEffect function is triggered and changes the movie ...

Conceal the entire <tr> tag if the child's child is present

My table situation is as follows: $('td:contains("label label-primary")').parent().hide(); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <tbody> <tr> <td> < ...

Issue: initial-es5 bundle size exceeds budget limit. The total size is 6.13 MB, which exceeds the 6.00 MB budget by 133.51 kB

I recently upgraded my Angular application to version 11. After running > ng build --prod I received the following output: √ Browser application bundle generation complete. √ ES5 bundle generation complete. Initial Chunk Files ...

What is the best way to extract specific information from a deeply nested document in MongoDB?

In my database, I have the following data structure. [ { _id: ObjectId("6386ef039775398be3620c76"), firstName: 'A', lastName: 'BA', age: 34, history: [ { disease: 'fever', cured: true }, ...

Does AngularJS have an Object-Relational Mapping tool?

While contemplating the idea of integrating bacon.js with AngularJS, I stumbled upon this interesting article: https://github.com/ProLoser/AngularJS-ORM However, my search for additional resources discussing the benefits and drawbacks of using bacon.js i ...

jQuery is failing to properly render dynamic content data identifiers

Need help with a dynamic HTML div <a data-id="17" onclick="getcustomer();"> <div class="note note-success"> <h4 class="block">A</h4> <p>Email : <a href="/cdn-cgi/l/email-protection" class="__cf_email__" ...

Which is more recommended to use in AJAX (XMLHttpRequest) - eventListener or readyStateChange method?

As I revisited a video from WWDC12 discussing advanced effects with HTML5, I couldn't help but notice that for the demo they utilized req.addEventListener("load",callback,true) instead of the usual onreadystatechange. This made me wonder: what differ ...

Issues with AngularJS functionality have been noticed in Chrome browsers on both Mac and Windows platforms, with Safari being

As I begin my journey into learning AngularJS, I encountered an unusual issue. The code snippet below is taken from an online tutorial on Github. Interestingly, the code functions flawlessly on Safari (MAC) but fails to load on Chrome. The same problem p ...

Setting up routes in Vue 2.0 - Avoid using 'new' for any side effects caused

Currently, I am setting up a vue project using the webpack template (npm install init webpack). However, I am encountering an error in the terminal: ERROR in ./src/main.js ✘ http://eslint.org/docs/rules/no-new Do not use 'new' for side effe ...

Integrating Gesture Handling in Leaflet JS for two-finger scrolling enforcement

Have you ever noticed that when you're using a mobile device and scrolling down a webpage with a Google map, the map goes dark and prompts you to "Use two fingers to move the map"? https://i.stack.imgur.com/4HD1M.jpg I am interested in incorporating ...

Implementing debouncing or throttling for a callback function in React using hooks, allowing for continuous updates without having to wait for the user to finish typing

Using React with Hooks and Formik to create a form that includes a preview of the content, I noticed a performance issue when rendering both elements simultaneously. Even though the form works smoothly by itself, it becomes slow and unresponsive when incor ...

What is the best method for creating numerous Popovers within a single ID?

Is it possible to create multiple popovers with the same ID? <div class="card-text"> <a href="#" id="seelabel" data-toggle="popover" data-trigger="hover" title="Inkscape" data-content= ...

Issue with Titanium: Unable to scroll within tableview

The tableview is not scrolling as expected. I tested it on a mobile device and the scrolling worked fine, but it doesn't seem to work on tablets. Please assist. CODE var win = Titanium.UI.createWindow({ title : 'Medall app', back ...

Using Ramda, learn how to transform a flat list into a hierarchical one

Looking to transform the given list into a hierarchical structure with nested children fields. The 'parentId' attribute has been omitted for clarity, as it will be used in the transformation process using Ramda's immutable behavior. const x ...

Creating a rotating HTML5 video and exporting the result as a canvas image

I'm currently using the jpeg_camera library to display an HTML5 Video on my website (https://github.com/amw/jpeg_camera) Here's how the video output looks in my HTML: <video autoplay="" src="blob:http://localhost:49209/41c42143-5d0e-4525-8fe ...

There seems to be an issue populating the array

My code includes an ajax call that looks like this: $.ajax({ type: 'POST', url: '../ws_BQS.asmx/ResultadosDimensionalByDate', data: '{"fecha":"' + fecha + '"}', dataType: 'json', conte ...