2

I want to have a single bootstrap 3 alert to show general error or success messages for all the operations a user can perform on a page. The page is divided in different sections with different controllers per section, something like this:

<body ng-app="app">
  <div ng-controller="securityController">
    [controller methods for change password, validate user section, ...]
    <div ng-controller="salesController"> 
      <div class="alert" ng-show="message.visible"><strong>{{message.title}}</strong>{{message.text}}</div></div>
      [controller methods for admin sales, admin products, admin retails, ...]
    </div>
  </div>
</body>

Then I want to be able to bind this html to all the models in the controllers who want to show a message when a user performs an action in the page (Ej. security messages when it interacts with securityController methods, validation messages when it interacts with salesController methods)

First I thought that cascading the controllers and making them have models with the name of the binding variables used in the alert HTML could work (Ej. having a $scope.message object in securityController and in salesController) but it didn't work and I don't really think that is the correct approach.

How can I achieve this?

2 Answers 2

2

Something similar I wanted to do with Bootstrap's modal, to be able to display it to user when any error occurs.

First a Service:

.service('ErrorService', function() {
    var error;

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

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

    this.clearError = function() {
        error = undefined;
    };
})

Then a directive which looks on the service's getError and displays itself if the service returns some value:

.directive('errorModal', ['ErrorService', 
    function(ErrorService) {
        return {
            link: function($scope, iElm, iAttrs, controller) {
                $scope.$watch(ErrorService.getError, function(newVal, oldVal) {
                    if (newVal) {
                        // service returned something, display this modal foe further!
                    }
                });
            }
        };
    }
]);

If you want to set the error, from any controller any other JS code (where you have injected the service of course!) just do:

ErrorService.setError(someError);

And the directive I have included only once in the HTML code in index.html:

<div error-modal></div>

Hope this helps.

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

4 Comments

In the $scope.$watch part of the directive, shouldn't it be ErrorService.setError instead of ErrorService.getError?
No. The getError returns the value and in the $scope.$watch we want to know (to watch) what the service returns (what it was set to earlier, from some other part of the app).
I forgot to mention the clearError, that is called after a Close button in the directive is clicked
Thanks! your answer and @guru's answer are the right approach but I chose guru's since its answer addresses my exact use case(bootstrap alerts).
1

Here is a sample code which I had written for one of my app.

Demo: http://plnkr.co/edit/pGhKOTtqFxpD4fukhQrl?p=preview

Directive:

app.directive('alert', function(alertService) {
  return {
    restrict: 'AE',
    link: function(scope, e, a, ctl) {
      scope.alert = alertService.alertObj;
    },
    template: '<div class="alert" ng-class="alert.type" ng-show="alert.show">{{alert.msg}}</div>'
  };
});

Service: Links multiple controllers with the directive.

app.service('alertService', function() {
  var me = this;
  me.alertObj = {
    show: false,
    msg: '',
    type: 'alert-success'
  };
  me.alertShow = false;
  me.alertTypes = ['alert-success', 'alert-info', 'alert-warning', 'alert-danger'];
  me.alert = function(type, msg) {
    me.alertObj.msg = msg;
    me.alertObj.type = me.alertTypes[type];
    me.alertObj.show = true;
  };
  me.success = function(msg) {
    me.alert(0, msg);
  };
  me.info = function(msg) {
    me.alert(1, msg);
  };
  me.warning = function(msg) {
    me.alert(2, msg);
  };
  me.danger = function(msg) {
    me.alert(3, msg);
  };
  me.hide = function() {
    console.log('hiding');
    me.alertObj.show = false;
  };
  return this;
});

controller: Sample controller

app.controller('ctl1', function($scope, alertService) {
  $scope.name = 'World';
  $scope.showAlert = function() {
    alertService.success("This is an success alert");
  };
});

HTML:

<alert></alert>
  <div ng-controller="ctl1">
    <button ng-click="showAlert()">ctl1 - Success alert</button>
  </div>
  <div ng-controller="ctl2">
    <button ng-click="showAlert()">ctl2 - Warning alert</button>
  </div>
  <div ng-controller="ctl3">
    <button ng-click="showAlert()">ctl3 - Danger alert</button>
  </div>
  <div ng-controller="ctl4">
    <button ng-click="showAlert()">ctl4 - Info alert</button>
    <button ng-click="hide()">Clear Alert</button>
  </div>

1 Comment

Wow! I didn't know you could initialize directives with services and then use service objects in the template! This is my chosen answer.

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.