Can I start the polling service by call ? AngularJS

849 views Asked by At

i have written a polling service in AngularJS and want to start the service if my post request is done.But if I call the gui, the poll service is active.

i have try to implement a start function, end function and call the start() function if the post request is done.. but it doesnt work :/

My poll service :

.factory('NotificationPollService',
['$http', '$q', '$interval',
function ($http, $q, $interval) {

    var deferred = $q.defer();
    var notification = {};

    notification.poller = $interval(function(id) {
        $http.get('http://localhost:9999/v1/jmeter/id', {cache: false})
        .success(function(data, status, headers, config) {
             return data;
        }, 10000);
    });

    notification.endPolling = function() {$interval.cancel(this.interval);};    

}])

and the controller which i post the request

.controller('HomeController',
['$scope', '$rootScope', 'SendJmeterFile', 'NotificationPollService',
function ($scope, $rootScope, SendJmeterFile , NotificationPollService) {

    $scope.upload = function() {

        var customArtifacts = "";
        var testDataBase = "";

        if($scope.jmeterFile.customArtifact == undefined){
            customArtifacts = null;
        } else {customArtifacts = $scope.jmeterFile.customArtifact.base64}

        if($scope.jmeterFile.testDataBase == undefined){
            testDataBase = null;
        } else {testDataBase = $scope.jmeterFile.testDataBase.base64}

        SendJmeterFile.upload($scope.jmeterFile.jmeter.base64, customArtifacts, $scope.jmeterFile.customProperties, $scope.jmeterFile.instanceConfiguration, $scope.jmeterFile.instances, $scope.jmeterFile.providerID, testDataBase)
            .then(function(data) {
                alert("Daten erfolgreich verschickt!");
                console.log(data);  
                NotificationPollService.poller(data.id)
                //.then(function(data) {
                    /*if(data.status == "SETUP")

                    if(data.status == "TEST")

                    if(data.status == "DONE")

                    if(data.status == "ERROR")
                }), function(data) {
                    })*/
            }, function(data) {
                alert("Fehler!");
                console.log(data);
            });     
    };
}])
2

There are 2 answers

4
Rogier Pennink On BEST ANSWER

One problem is that $interval() is called immediately upon injection into your controller. Your hunch to implement a 'Start' method or something similar was a good one - but you can probably simplify it even more by letting the factory return a function. Then you can just instantiate that function in your controller as many times as you need a Poller.

However, there are more problems. A promise can only be resolved once, and since you execute a HTTP request multiple times, my guess is that you want to be 'notified' of state changes until the state is marked as 'Done'. You're currently putting the responsibility for checking the state with the controller. If all you want is to be notified of "error" and "success" steps however, it is probably much better to let the Poller service be responsible for interpreting the state information that comes back from your service, and simply depend on standard promise behaviour in your controller. I opted to show an example of the latter case:

UPDATE: sample plnkr here: http://plnkr.co/edit/e7vqU82fqYGQuCwufPZN?p=preview

angular.module('MYMODULENAMEHERE')
.factory('NotificationPoller',
    ['$http', '$q', '$interval',
    function ($http, $q, $interval) {

        return poller;

        function poller(id) {
            var _this = this;
            var deferred = $q.defer();

            var interval = $interval(function() {
                $http
                    // I assumed you actually want to use the value of 'id' in your
                    // url here, rather than just the word 'id'.
                    .get('http://localhost:9999/v1/jmeter/' + id, {cache: false})
                    .then(function(data, status, headers, config) {
                        // I commented out the following statement. It is meaningless because
                        // you can't do anything with the return value since it's an anonymous
                        // function you're returning it from. Instead, you probably meant to 
                        // use the promise to return the data.

                        // return data;

                        if(data.status == "SETUP") {
                            deferred.notify(data);
                        }
                        else if(data.status == "TEST") {
                            deferred.notify(data);
                        }
                        else if(data.status == "DONE") {
                            _this.endPolling(); // Automatically stop polling when status is done
                            deferred.resolve(data);
                        }
                        else { // data.status == "ERROR" (or anything else that's not expected)
                            _this.endPolling(); // Automatically stop polling on error
                            deferred.reject(data);
                        }                       
                    }, function(data) {
                        _this.endPolling();
                        deferred.reject(data);
                    });
            }, 10000);

            this.endPolling = function() {
                $interval.cancel(interval);
            };

            // Make the promise available to calling code
            this.promise = deferred.promise;
        };
}])

Now your controller can much more easily use your polling service. Here's an example of a stripped-down controller using your polling service, for clarity:

angular.module('MYMODULENAMEHERE')
.controller('HomeController', [
    'NotificationPoller',
    function(NotificationPoller) {

        var some_id = 207810;

        var poller = new NotificationPoller(some_id);
        poller.promise.then(onSuccess, onError, onNotify);

        function onSuccess(data) {
            // data.status == "DONE"
        };

        function onError(data) {
            // data.status == "ERROR"
        };

        function onNotify(data) {
            // data.status == "TEST" || data.status == "SETUP"
        };

    }]);

As you see, the factory has received a little more responsibility this way, but your controller doesn't need to be aware of the details of all the statuses that the backend can send anymore. It just uses standard promises.

5
antonama On

You try to call NotificationPollService.poller(data.id) which is Promise, actually, because previously in NotificationPollService you assigned notification.poller like so

notification.poller = $interval(function(id) {
    $http.get('http://localhost:9999/v1/jmeter/id', {cache: false})
    .success(function(data, status, headers, config) {
         return data;
    }, 10000);
});

Now your notification.poller is a return value of $interval function. To make it work you should wrap the function so you could actually pass an id to it.