0

I have a simple JSFiddle:

<div ng-controller="MainCtrl as mainCtrl">
    <div ng-show="mainCtrl.visible" ng-click="mainCtrl.swap()">Can you see me?</div>
    <div see-me></div>
</div>

angular.module('AngularTestApp', [])
    .controller('MainCtrl', [function () {
        var self = this;
        self.visible = true;
        self.swap = function() {
            self.visible = ! self.visible;
        };
    }])
    .directive('seeMe', [function () {
        return {
            template: 'or me?',
            link: function (scope, element, attrs) {
                attrs.$set('ng-show', 'mainCtrl.visible');
                attrs.$set('ng-click', 'mainCtrl.swap()');
        }
    };
}]);

Since the default value for a scope on a directive's definition object is false I would expect the parent's scope to be available and thus for attrs.$set('ng-click', 'mainCtrl.swap()'); to work, but it does not fire when I click the div. Why?

(N.B. I tried adding $compile as per ppa's answer to 'AngularJS - ng-click in directive's link function' but that had no effect.)

Community
  • 1
  • 1
dumbledad
  • 16,305
  • 23
  • 120
  • 273

2 Answers2

1

Setting attributes on an element doesn't process any directives. You'll have to use the $compile service to compile the new template with the current scope and replace the current element with the compiled element.

.directive('seeMe', ['$compile', function ($compile) {
        return {
            template: 'or me?',
            link: function (scope, element, attrs) {
                var newElement = $compile('<div ng-show="mainCtrl.visible" ng-click="mainCtrl.swap()">or me?</div>')(scope);
                element.replaceWith(newElement);
        }
    };

JSFiddle

c.P.u1
  • 16,664
  • 6
  • 46
  • 41
  • Wow, thanks for that. This looks like a handy way to rewrite code that would have used `replace` before it was deprecated too. – dumbledad Feb 20 '15 at 11:12
1

In the question I mention trying $compile but I think I messed up injection when I tried that. c.P.u.1's answer show's how I should have done it. Here's a version of c.P.u.1's answer which does not replace the current element but compiles it after the additional attributes are added. Note that I need to remove the original directive attribute avoid infinite compile loop (see Ilan Frumer's answer to 'Angular directive how to add an attribute to the element?').

HTML

<div ng-controller="MainCtrl as mainCtrl">
    <div ng-show="mainCtrl.visible" ng-click="mainCtrl.swap()">Can you see me?</div>
    <div see-me></div>
</div>

JavaScript

angular.module('AngularTestApp', [])
.controller('MainCtrl', [function () {
    var self = this;
    self.visible = true;
    self.swap = function() {
        self.visible = ! self.visible;
    };
}])
.directive('seeMe', ['$compile', function ($compile) {
    return {
        template: 'or me?',
        link: function (scope, element, attrs) {
            element.removeAttr('see-me');
            attrs.$set('ng-show', "mainCtrl.visible");
            attrs.$set('ng-click', "mainCtrl.swap()");
            $compile(element)(scope);
        }
    };
}]);

(JSFiddle here).

Community
  • 1
  • 1
dumbledad
  • 16,305
  • 23
  • 120
  • 273