2

I'm using Angular 1.08, hence I need to use responseInterceptors.

First the code.

Interpreter:

app.factory('errorInterceptor', ['$q', 'NotificationService', function ($q, NotificationService) {
    return function (promise) {
        return promise.then(function (response) {
            // do something on success
            return response;
        }, function (response) {
            // do something on error
            alert('whoops.. error');
            NotificationService.setError("Error occured!");

            return $q.reject(response);
        });
    }
}]);

app.config(function ($httpProvider) {
    $httpProvider.responseInterceptors.push('errorInterceptor');
});

NotificationService:

app.service("NotificationService", function () {
    var error = '';

    this.setError = function (value) {
        error = value;
    }

    this.getError = function () {
        return error;
    }

    this.hasError = function () {
        return error.length > 0;
    }
});

Directive error-box:

app.directive("errorBox", function (NotificationService) {
    return {
        restrict: 'E',
        replace: true,
        template: '<div data-ng-show="hasError">{{ errorMessage }}</div>',
        link: function (scope) {
            scope.$watch(NotificationService.getError, function (newVal, oldVal) {
                if (newVal != oldVal) {
                    scope.errorMessage = newVal;
                    scope.hasError = NotificationService.hasError();
                }
            });

        }
    }
});

The problem: When I use <error-box> at multiple places, all these boxes will display the error message. This is not my intent. I'd like to show only the error-box where the exception occurs.

For example, I have a directive which shows a list of transactions. When fetching the transactions fails, I want to show the error-box which is declared in that part. I also have a directive where I can edit a customer. This directive also contains the error-box tag.

What happens is when saving a customer fails, both error-boxes are displayed, however, I only want the error-box of the customer to be displayed.

Does someone has an idea to implement this?

1 Answer 1

3

Angular services are Singleton objects, as described in the angular docs here. This means that Angular only creates one single "global" instance of a service and uses that same instance whenever the given service is requested. That means that Angular only ever creates one single instance of your NotificationService services and then will supply that one instance to every instance of your errorBox directive. So if one directive updates the NotificationService's error value, then all of the <error-box directives will get that value.

So, you're going to have to either create multiple notification services for each type of error (ie TransactionNotification and CustomerNotification, etc) or add different methods to your main NotificationService that would allow you to set only specific alerts (such as NotificationService.setCustomerError() or NotificationService.setTransactionError()).

None of those options are particularly user-friendly nor clean, but I believe (given the way you've set up your service), that's the only way to do it.

UPDATE: After thinking about it, I might suggest just dropping your whole NotificationService class and just using $scope events to notify your <error-box> elements when an error occurs:

In your 'errorInterceptor':

app.factory('errorInterceptor', ['$q', '$rootScope', function ($q, $rootScope) {
    return function (promise) {
        return promise.then(function (response) {
            // do something on success
            return response;
        }, function (response) {
            // do something on error
            alert('whoops.. error');
            var errorType = ...; // do something to determine the type of error
            switch(errorType){
                case 'TransactionError':
                    $rootScope.$emit('transaction-error', 'An error occurred!');
                    break;
                case 'CustomerError':
                    $rootScope.$emit('customer-error', 'An error occurred!');
                    break;
                ...
            }

            return $q.reject(response);
        });
    }
}]);

And then in your errorBox directive:

link: function (scope, element, attrs) {
        var typeOfError = attrs.errorType;
        scope.$on(typeOfError, function (newVal, oldVal) {
            if (newVal != oldVal) {
                scope.errorMessage = newVal;
            }
        });

    }

And then in your view:

<error-box error-type="transaction-error"></error-box>
<error-box error-type="customer-error"></error-box>

Does that make sense?

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

1 Comment

Thanks for the extensive answer. This gives me definitely something to think about.

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.