MelkorNemesis
MelkorNemesis

Reputation: 3435

Setting up catching event in directive

I have a directive for flashmessages

'use strict';

angular.module('diplomovaPraceFrontendApp')
.directive('flashMessages', () ->
    directive:
        restrict: 'E'
        replace: true
        template: '<div ng-repeat="m in messages" id="flash-messages">' +
                    '<div class="alert {{m.level}}">' +
                    '<span class="">{{m.text}}</span>' +
                    '</div>' +
                    '</div>'
        controller: ($scope, $rootScope) ->
            $rootScope.$on('flash:message', (_, messages, done) ->
                $scope.messages = messages
                done()
        )
)

and when I call in my controller $rootScope.$emit('flash:message', messages, someFunction); it isn't caught by $rootScope.$on() set up in directive, although if I put this in application.run() it works correctly.

Any ideas what I'm missing? Thanks for any advice

I have edited the question:

I do of course use an shared service, here's my code http://pastie.org/private/es25rvo0zvejuw9yx3acja (sorry, gist.github.com seems to be broken for me atm)

I was following this tutorial http://chiragchamoli.com/post/61277736964/building-a-flash-message-with-angular-js

Though it seems it doesn't call the directive at all, since replace is set to true and I still see <flash-messages> in code inspector.

Plunkr version: http://plnkr.co/edit/buRaguEyTMuhUM9Z4Jsw?p=preview

Upvotes: 1

Views: 1071

Answers (2)

BahamutWC
BahamutWC

Reputation: 194

I already gave a fix in #angularjs earlier, but here it is for posterity:

http://plnkr.co/edit/Fb9FYSXgU0t93w7i2B8q?p=preview

The problem is that MainCtrl is instantiated before the directive, so the $scope event gets fired before the directive sets a listener on $scope, so the directive never gets the event listened to here.

Upvotes: 1

mortalapeman
mortalapeman

Reputation: 1425

The problem is that your non directive controller function is called before the directive controller. Thus, the message is being sent before the the directive has registered for alerts.

A simple solution to this would be, instead of using events, use a shared service. Services are singletons, so any state is shared between all usages of that service. Using a service only makes sense if your all of your flashMessage directives need a shared state. If this solution does not fit your needs, help me better understand your requirements.

Working plunker

Javascript:

var app = angular.module('plunker', [])

.controller('MainCtrl', function ($scope, alertsService) {
    alertsService.add({
        text: 'I am an alert',
        level: 'high'
    });
})

.service('alertsService', function () {
    this.alerts = [];
    this.add = function (message) {
        this.alerts.push(message);
    }.bind(this);
})

.directive('flashMessages', function (alertsService) {
    return {
        restrict: 'E',
        replace: true,
        template: '<div ng-repeat="m in messages" id="flash-messages">' +
            '<div class="alert {{m.level}}">' +
            '<span class="">{{m.text}}</span>' +
            '</div>' +
            '</div>',
        scope: true,
        link: function ($scope) {
            $scope.messages = alertsService.alerts;
        }
    };
});

HTML:

  <body ng-controller="MainCtrl">
    <flash-messages></flash-messages>    
  </body>

Upvotes: 0

Related Questions