Dine
Dine

Reputation: 7283

What is the best way to do error handling globally in an angular.js app?

I have an app which makes http calls using various services I created. When the server request fails or when the api returns an error attribute I would like to display these errors on the top of my page.

I can see in the angular documentation that error can best be displayed this way, which makes sense:

<div ng-controller="AlertDemoCtrl">
  <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">{{alert.msg}}</alert>
</div>

And in the AlertDemoCtrl:

  $scope.addAlert = function() {
    $scope.alerts.push({msg: "Another alert!"});
  };

  $scope.closeAlert = function(index) {
    $scope.alerts.splice(index, 1);
  };

The thing is that I'm not sure how to push the errors into the alerts within the AlertDemoCtrl since the http request is happening within the services where I don't have access to the AlertDemoCtrl. Do I need to broadcast events in order to add them into the AlertDemoCtrl or is there a way to inject a controller into a service? Or do I need to add the addAlert function into $rootScope?

Appreciate any advice, thank you!

Upvotes: 3

Views: 2678

Answers (1)

Nikos Paraskevopoulos
Nikos Paraskevopoulos

Reputation: 40298

The way I have implemented this is with a messageService that exposes the following interface:

{
    messages:      /* an array of all messages */,
    addMessage:    /* function(severity, text) */,
    removeMessage: /* function(messageObject) */,
    // other stuff, irrelevant to current topic
}

Each message object has a text, a "severity" (ERROR, WARNING etc) and a remove method. I have also added an option for messages to timeout and be removed automatically.

Any controller that needs to add messages, uses the messageService. A messages controller exposes the messages property of the service to its scope and the template ng-repeats over them (I want to display messages at the top of the page). Using bootstrap styles:

<div id="messageContainer" ng-controller="messages">
    <div alert
         ng-repeat="msg in messages"
         type="msg.severity"
         close="closeMsg($index)"
    >
        {{msg.text}}
    </div>
</div>

And the controller:

app.controller("messages", ["$scope", "messageService"],
function($scope, messageService) {
    $scope.messages = messageService.messages,
    $scope.closeMsg = function(index) {
        $scope.messages[index].remove();
    };
});

Now, if a service needs to add a message, it can interact with the messageService. I'd rather not have services interact with the UI though; I think it is better for a service to return a list of messages and for the controller to deal with them as it wishes.

Upvotes: 10

Related Questions