通过指令的 link 函数添加时,ng-click 和控制器访问会发生什么

What happens to ng-click and controller access when added by a directive's link function

我有 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()');
        }
    };
}]);

由于指令定义对象上 scope 的默认值是 false 我希望父级的范围可用,因此 attrs.$set('ng-click', 'mainCtrl.swap()'); 可以工作,但确实如此单击 div 时不触发。为什么?

(N.B。我尝试按照 ppa's answer to 'AngularJS - ng-click in directive's link function' 添加 $compile,但没有效果。)

在元素上设置属性不会处理任何指令。您必须使用 $compile 服务用当前 scope 编译新模板,并用编译后的元素替换当前元素。

.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

在问题中我提到尝试 $compile 但我认为我在尝试时搞砸了注射。 show's how I should have done it. Here's a version of 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).