0

How is the angular way to show visual feedback to the user that the appp is waiting for an answer from the server?

Currently i have factory with following code

app.factory('MyAppFact', ['$http', '$q', 
function($http, $q) {
    function _success(data, status) {
        document.body.classList.remove('waitserver')
        if (data.status == 'OK') {
            this.resolve(data);
        } else {
            this.reject(data);
        }   
    }
    function _error(data, status) {
        document.body.classList.remove('waitserver')
        this.reject(status})    
    }
    return {
        changeLocale: function(locale){
            var d = $q.defer();
            document.body.classList.add('waitserver');
            $http.get('/changeLocale/'+locale).success(_success.bind(d), 
                _error.bind(d));
            return d.promise;
        },
        login: function(uname, passwd, keep) {
            var d = $q.defer();
            document.body.classList.add('waitserver');
            $http.post('/login', {uname:uname, passwd:passwd, keep:keep}
                ).success(_success.bind(d), _error.bind(d));
            return deferred.promise;
        },
        register: function(user) {
            var d = $q.defer();
            document.body.classList.add('waitserver');
            $http.post('/register', {user:user}).success(_success.bind(d), 
                _error.bind(d));
            return deferred.promise;
        },

        ...

    }
}]);

Although this code works, I am adding a css class in to the document body, while according to the angularjs docs, I am not supposed to change the DOM in a factory method, thereby violating the clear separation of the MVC

But I don't see how I can accomplish the separation in this case.

1

1 Answer 1

0

You can combine some global state, a ng-class directive (applied to the <body> or the wrapper element of your dynamic, Angular-managed content) and the HTTP interceptors described here.

So the global state would be something like an active requests counter, implemented as a service or a member of the $rootScope. Lets consider the 2nd for simplicity, although the 1st seems more correct:

$rootScope.activeRequestsCounter = 0;

You register the interceptors that manipulate the counter:

$provide.factory('myHttpInterceptor', function($rootScope) {
    function increase() {
        $rootScope.activeRequestsCounter++;
    }

    function decrease() {
        $rootScope.activeRequestsCounter--;
    }

    return {
        request: increase,
        requestError: decrease,
        response: decrease,
        responseError: decrease
    };
});


// in some config block:
$httpProvider.interceptors.push('myHttpInterceptor');

In the HTML:

<body ng-class="{waitserver: activeRequestsCounter &gt; 0}">

This is the principle of operation, details may need refinement. What you gain is that you no longer need to worry about adding/removing the class in each service call. You can invoke multiple services and the counter will update correctly. And you do not manipulate DOM inside the services (cleaner code).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I will do it slightly different, but setting a $rootScope variable does the trick

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.