gpt4 book ai didi

angularjs - 测试 ng-transclude 不起作用

转载 作者:行者123 更新时间:2023-12-04 08:24:29 24 4
gpt4 key购买 nike

我正在编写两个指令来包装 ui-bootstrap 的 tabset 和 tab 指令。
为了将我的指令的内容传递给包装的指令,我在它们中都使用了嵌入。
这很好用,唯一的问题是我没有编写一个检查它的测试。我的测试使用替换指令作为包装指令的模拟,我在每次测试之前使用 $compileProvider 替换它。

测试代码如下所示:

beforeEach(module('myModule', function($compileProvider) {
// Mock the internally used 'tab' which is a third party and should not be tested here
$compileProvider.directive('tab', function() {
// Provide a directive with a high priority and 'terminal' set to true, makes sure that
// the mock directive will get executed, and that the real directive will not
var mock = {
priority: 100,
terminal: true,
restrict: 'EAC',
replace: true,
transclude: true,
template: '<div class="mock" ng-transclude></div>'
};

return mock;
});
}));

beforeEach(function() {
inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
});
});

beforeEach(function() {
$scope = $rootScope.$new();
});

afterEach(function() {
$scope.$destroy();
});

it('Places the enclosed html inside the tab body', function() {
element = $compile("<div><my-tab>test paragraph</my-tab></div>")($scope);
$scope.$digest();

console.log("element.html() = ", element.html());

expect(element.text().trim()).toEqual("test paragraph");
});

我的指令模板如下所示:
<div><tab><div ng-transclude></div></tab></div>

指令模块看起来像这样:
angular.module('myModule', ['ui.bootstrap'])

.directive('myTab', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: 'templates/my-tab.tpl.html',

scope: {
}
};
});

打印到控制台的结果是这样的:
LOG: 'element.html() = ', '<div class="ng-isolate-scope" id=""><div id="" heading="" class="mock"><ng-transclude></ng-transclude></div></div>'

关于为什么不发生嵌入的任何想法(同样,它在测试之外工作得很好)?

更新

从那以后,我转向了其他事情和指令,并再次遇到了这个问题,但现在更重要的是,我放置在父指令中的指令在其链接功能中需要父 Controller 。

我对此进行了更多研究,结果发现由于某种原因,编译模拟指令不会创建嵌入内容的实例。
我知道这一点的原因是,我已经在两个指令(模拟和嵌入指令)的每个钩子(Hook)中都放置了一个打印输出,即编译、预链接、后链接和 Controller 构造函数,我看到只有打印输出来自模拟指令。

现在,这是真正有趣的部分:我尝试在模拟指令的链接函数中使用 transclude 函数来“强制”编译 transcluded 指令,它奏效了! (另一个证明它不是隐式发生的)。
你问的问题在哪里?好吧,它仍然不起作用。这一次,由于 transcluded 指令的链接功能失败,因为它没有找到模拟指令的 Controller 。什么 ?!

这是代码:

代码
var mod = angular.module('MyModule', []);

mod.directive('parent', function() {
return {
restrict: 'E',
replace: true,
template: '<div class="parent">...</div>',

controller: function() {
this.foo = function() { ... };
}
};
});

mod.directive('child', function() {
return {
restrict: 'E',
require: '^parent',

link: function(scope, element, attrs, parentCtrl) {
parentCtrl.foo();
}
};
});

测试
describe('child directive', function() {
beforeEach(module('MyModule', function($compileProvider) {
$compileProvider.directive('parent', function() {
return {
priority: 100,
terminal: true,
restrict: 'E',
replace: true,
transclude: true,

template: '<div class="mock"><ng-transclude></ng-transclude></div>',

controller: function() {
this.foo = jasmine.createSpy();
},

link: function(scope, element, attrs, ctrls, transcludeFn) {
transcludeFn();
}
};
});
}));
});

此测试失败并显示错误消息,例如:

Error: [$compile:ctreq] Controller 'parent', required by directive 'child', can't be found!



任何想法、想法、建议将不胜感激。

最佳答案

好吧,这可能是 SO 历史上最短的赏金......

问题在于 terminal: truepriority: 100模拟指令的属性。我的印象是(来自我在网上阅读的一篇关于如何模拟指令的文章),这些属性会导致编译器停止编译具有相同名称的指令并优先考虑首先评估的模拟指令。
我显然错了。看thisthis ,很明显:

  • '终端' 停止 任意 尚未处理的其他指令
  • 'priority' 用于确保在模拟指令之前处理模拟指令

  • 问题在于,这会导致所有其他处理停止,包括 ng-transclude指令,其默认优先级为 0 .

    但是,删除这些属性会导致一切都崩溃,因为这两个指令都已注册,等等(我不会用所有血淋淋的细节给你带来负担)。为了能够删除这些属性,这两个指令应该位于不同的模块中,并且它们之间应该没有依赖关系。简而言之,在测试 child 时指令,唯一名为 parent 的指令评估的应该是模拟指令。
    为了支持现实生活中的使用,我在系统中引入了三个模块:
  • child 的模块指令(无依赖关系)
  • parent 的模块指令(无依赖关系)
  • 一个没有内容但同时依赖于 child 的模块和 parent模块,这是您需要在代码中添加为依赖项的唯一模块

  • 差不多就是这样。我希望它可以帮助遇到此类问题的其他人。

    关于angularjs - 测试 ng-transclude 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28871825/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com