Reputation: 7283
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
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-repeat
s 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