【问题标题】:Why does the link function of my directive never get called?为什么我的指令的链接函数永远不会被调用?
【发布时间】:2014-07-06 08:14:40
【问题描述】:

我有这个指令:

    hpDsat.directive('ngElementReady', [function() {
        return {
            restrict: "A",
            link: function($scope, $element, $attributes) {
                // put watches here.
                console.log(" WHAT THE @#%*%$??? ");
                $scope.$eval($attributes.ngElementReady);
            }
        };
    }]);

我从来没有看到console.log 的输出。我正在声明这样的元素:

<div data-ng-element-ready="console.log(' ------------------------------- COMPILED! ')" data-ng-if="analysis.type" data-ng-show="showBasicHtml" data-ng-include="analysis.type+'Content.html'"></div>

是的,我在声明div 元素所在的控制器之前声明了指令。元素出现,ngShow 和 ngInclude 正常工作,加载的模板中的任何内容也正常工作(更多指令、控制器、{{expressions}} 等)。

如果我用编译函数执行它,编译函数确实工作,但仍然不是链接函数:

    hpDsat.directive('ngElementReady', [function() {
        return {
            restrict: "A",
            compile: function($element, $attributes) {
                console.log("This I do see."); // THIS WORKS!!
                return function($scope) {
                    // put watches here.
                    console.log("But not this. Why???"); // DOESN'T WORK!!
                    $scope.$eval($attributes.ngElementReady);
                };
            }
        };
    }]);

编译函数的console.log运行正常,但是返回的链接函数仍然没有被执行。

知道为什么链接函数可能不会被触发吗?

【问题讨论】:

  • 发现问题。我在 Eduard Gamonal 的回答中对此进行了评论。

标签: javascript html angularjs angularjs-directive angularjs-scope


【解决方案1】:

错误可能在其他地方。我在jsfiddle 中尝试过,第一个版本有效。

eval()

无论如何,您可能对$scope.$eval() 的作用有误解:

$scope.$eval() 针对范围评估 angularjs 代码。在 angularjs 中运行任意 js 代码的 JavaScript 的 eval() 函数是 $window.eval()。更多信息在这里:Angular.js: How does $eval work and why is it different from vanilla eval?

我测试了与控制器隔离的指令:

<div data-ng-element-ready="console.log('COMPILED!')"></div>

和指令:

app.directive('ngElementReady', ['$window', function($window) {
return {
    restrict: "A",
    link: function($scope, $element, $attributes) {
        console.log("Reached the link fn", $attributes);
        $window.eval($attributes.ngElementReady);
    }
};
}]);

我确实得到了“到达链接 fn”的值,$attributes 是正确的:

Reached the link fn Object { $$element={...}, $attr={...},  
ngElementReady="console.log('COMPILED!')", more...}

$window.eval() 返回COMPILED!

here 使用控制器。

无论如何,使用eval() 执行以属性编写的代码看起来很危险。任何人都可以修改 DOM 以在其中运行代码。至少确保它不会影响任何其他用户或服务器端。

用 ng-if 重现问题

在第一条评论后编辑: 我尝试让 ng-if 表达式评估为 false here 这次它不显示消息。 这可能是因为为了评估 ng-if,你必须先编译指令。否则,这只是 anuglarjs 不知道的代码。但是,因为它是从 DOM 中移除的,所以它永远不会到达链接函数。

AngularJS函数的执行顺序

一般来说,执行顺序是这样的(Josh David Miller explains it:

<div directive1>
  <div directive2>
    <!-- ... -->
  </div>
</div>

现在 AngularJS 将通过按特定顺序运行指令函数来创建指令:

directive1: compile
  directive2: compile
directive1: controller
directive1: pre-link
  directive2: controller
  directive2: pre-link
  directive2: post-link
directive1: post-link

【讨论】:

  • 感谢 eval 的提示。我不会全部使用那个,但是在它执行之前的 console.log 行,即使 $eval 不起作用,对吧?我不明白为什么我的没有。问题是我有大量的代码,所以我真的不能摆弄它。如果我做一个小提琴,它可能会起作用,因为它很简单。我一般想知道是什么导致链接功能被忽略。
  • 也许你可以开始检查ng-if?通常你不会在同一个指令中使用 ng-if 和 ng-show,因为 ng-if 会从 DOM 中删除元素,而 ng-show 只是隐藏它。
  • 嘿@trusktr 我编辑了我的答案给你一些提示。检查您的 analysis.type 变量的值。也许你可以强制它为真,看看会发生什么,或者删除ng-if 属性?
  • 感谢您的洞察力!你帮我找到了问题:如果 ngInclude 指令中使用的 analysis.type 的值没有导致找到匹配的模板,那么我的 ngElementReady 指令的链接函数不会执行。一旦我将 analysis.type 的值(在将来的某个时间)设置为导致找到模板的某个值,我就会看到链接函数输出。这实际上很好,因为它可以让我在“元素准备好”时运行东西。
猜你喜欢
  • 2013-07-22
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多