AngularJS deferred promise in Jolokia request

346 views Asked by At

I have an application as a plugin in the Hawtio environment. The requirement is to use Jolokia requests, instead of using direct $http service calls.

So I have factory/service that has a retrieve function.

app.factory('myService', function($q, jolokia) {
    data: {
        list: []
    },
    retrieve: function() {

        var self = this;

        // var deferred = $q.deferred();

        jolokia.request({
            type: 'exec',
            mbean: mybean.mbean,
            operation: 'ops',
            arguments: [...]
        }, {
            method: 'POST',
            success: function(response) {
                var temp = [];

                /* assign values to temp from response */
                self.assignValuesToList(temp);

                /* log shows data.list is loaded by values */
                log("[service] " + self.data.list); // Hawtio uses a different logger

                // deferred.resolve();
            }   
        }, {
            error: function(error) {
                // error handling here

               // deferred.reject(error);   
            }
        });

        // return deferred.promise;
    }
});

This is my controller (the service is being reused by other controllers, that's why I have to re-assign the myService.data.list eventhough myController's scope already has control over it):

app.controller('myController', function($scope, myService) {

    $scope.ctrl.copyOfList = [];

    angular.extend($scope, myService);

    $scope.init = function() {
        $scope.search();
        log("[after search] " + $scope.ctrl.copyOfList);
    };

    $scope.search = function {

        $scope.retrieve();
        $scope.ctrl.copyOfList = $scope.data.list;
        $scope.$apply();

        log("[search] " + $scope.ctrl.copyOfList);
    };
});

and html:

<div ng-controller='myController' ng-init='init()'>

    <table>
        <thead>...</thead>
        <tbody>
            <tr ng-repeat='entry in ctrl.copyOfList'>
            ...
            </tr>
    </table>

</div>

This is the sequence of my logs:

[search] [] // empty
[after search] [] // empty
[service] [...] // service.data.list has values fetched by jolokia request from server

and the table is empty.

Because of asynchronous issue at hand, I tried to use promise (just uncomment the deferred lines of the service above). My controller becomes

app.controller('myController', function($scope, myService) {

    $scope.ctrl.copyOfList = [];

    angular.extend($scope, myService);

    $scope.init = function() {
        $scope.search();
        log("[after search] " + $scope.ctrl.copyOfList);
    };

    $scope.search = function {
        $scope.retrieve().
        then(function() {

            $scope.ctrl.copyOfList = $scope.data.list;
            log("[controller] " + $scope.ctrl.copyOfList);

            $scope.$apply();

        }, function(error) {
            // error handling here
        });

        log("[after promise] " + $scope.ctrl.copyOfList);
    };
});

And now my logs looks like:

[after promise] []
[after search] []
[service] [...]

// [controller] [...] log does not execute

and the table is still empty. What's more confusing here is before I leave the page that uses myController, the [controller][...] log will print on console and will write the contents of $scope.ctrl.copyOfList and populates the table instantaneously then suddenly changes page.

(I also tried using deferred.resolve(self.data.list) instead of deferred.resolve(), including the necessary changes on the controller, but it didn't matter, same result though).

So anyone can here who can figure out what's happening, and what could possibly be the solution here? Thanks.

1

There are 1 answers

1
Stan Lewis On BEST ANSWER

In the jolokia success/error callback you need a $scope.$apply() to fire angular's event loop. In a service like this I usually inject $rootScope and use Core.$apply($rootScope)