TL; DR:
在指令的templateUrl方法中使用attr值,在使用子指令时尚未插入attr。最终结果是文字{{attrName}}/something.html
。
全文: 我有一个外部指令,其中包含内部指令。诀窍是,这些内部指令也是可以在不知道父母的情况下自己生活的项目。
规则很简单:
的index.html:
<div zoo feeding-time="8am" template-base="/templates"></div>
OR - index.html也可以是:gorilla可以明确指定attr值,因为它不是继承
<div gorilla template-base-url="/templates"></div>
Zoo.html - 它将自己的配置传递给gorilla
<div gorilla template-base-url="{{templateBaseUrl}}"></div>
动物园directive.js
angular.module("app").directive("zoo", [function() {
return {
restrict: "A",
scope: true,
templateUrl: function(element, attrs) {
// THIS ONE NEVER FAILS BECAUSE ITS NEVER INTERPOLATED
var base = attrs.templateBaseUrl;
return base + "/zoo.html";
},
link: function(scope, element, attrs) {
// its my job to give gorilla a templateURL in this case
scope.templateBaseUrl = attrs.templateBaseUrl;
}
};
}]);
gorilla.html
angular.module("app").directive("gorilla", [function() {
return {
restrict: "A",
scope: true,
templateUrl: function(element, attrs) {
// THIS ONLY FAILS WHEN INCLUDED BY ZOO.HTML
// AND THEN, ONLY SOMETIMES. RACE CONDITION? PRIORITY?
// DOES NOT FAIL WHEN INCLUDED BY INDEX.HTML DIRECTLY
var base = attrs.templateBaseUrl;
return base + "/gorilla.html";
}
};
}]);
这很有效。有时。有时,{{templateBaseUrl}}
方法使用文字tempateUrl
。只有当大猩猩attrs.templateBaseUrl
方法使用templateUrl
时,我才能跟踪它,attrs.templateBaseUrl
它还没有被插值。< / p>
因此,gorilla.link()
在插入{{templateBaseUrl}}
和kaboom之前运行。 404 at&#34; {{templateBaseUrl}} / gorilla.html&#34;
我该如何避免这种情况?
https://docs.angularjs.org/error/ $编译/ tpload?P0 =%7B%7BtemplateBaseUrl%7D%7D%2Fgorilla.html
我在每个项目依赖的提供程序中都有这个baseUrl东西,但它与此简化版本具有相同的效果。它必须是解析订单问题。
答案 0 :(得分:4)
您的方法失败,因为templateUrl
函数必须在控制器的“编译”阶段之前运行(如果没有,则无法编译模板)。使用嵌套指令,首先运行所有编译函数,然后运行链接函数。我发现下面的图表可以作为使用嵌套指令时“运行时什么时候运行”的参考 - 它来自关于主题的公平in depth article - 一个很好的阅读。
http://www.jvandemo.com/content/images/2014/Aug/cycle-2.png
考虑到这一点,很明显,当你的gorilla指令正在编译时,动物园的链接功能还没有运行,这意味着范围值甚至没有设置,更不用说内插到属性中了。
看起来您将不得不自己获取并编译模板。您可以使用angular $templateRequest
来确保模板正确缓存。我们可以通过仅使用范围中的值来避免插值是否已经发生(我使用了隔离范围,因为它使事情变得不那么模糊,并且通常是更好的实践,但如果你想要你可以只使用范围继承)。 / p>
免责声明:以下代码已经编写而没有运行它,肯定会包含拼写错误和错误!希望你能看到逻辑......
angular.module("app")
.directive("gorilla", function($templateRequest, $compile) {
return {
restrict: "A",
// set up an isolate scope
scope: {
tplBaseUrl: '='
},
link: {
pre: function (scope, elem, attr) {
// Decide if the url is directly set or is dynamic
var baseUrl = scope.tplBaseUrl ? scope.tplBaseUrl : attr.tplBaseUrl;
// request the template
$templateRequest(baseUrl + '/gorilla.html')
.then(function (response) {
tpl = response.data;
// compile the html, then link it to the scope
$elem = $compile(tpl)(scope);
// append the compiled template inside the element
elem.append($elem);
});
},
post: function (scope, elem, attr){
// you can put your normal link function code in here.
}
}
};
});
请注意,预链接函数的第一行基本上检查是否存在使用您传递的名称设置的范围变量,如果没有,则假设您已经为其指定了url字符串(因此使用属性值)。这可能不是最好的方法 - 我很想使用两个不同的属性,但这取决于你。
重要的是(再次参考图表!),父(zoo)指令必须在其预链接函数中设置模板库的值,否则当子指令运行的链接函数值为undefined
。
您可以在此处使用类似于子指令,或使用您的原始方法。此代码已简化,以提供在预链接期间如何设置tplBaseUrl
的示例。
angular.module("app")
.directive("zoo", function() {
return {
restrict: "A",
template: '<div gorilla tpl-base-url="tplBaseUrl"></div>',
link: {
pre: function (scope, elem, attr) {
// make sure it is set here!
scope.tplBaseUrl = "/templates";
},
post: function (scope, elem, attr){
// link logic
}
}
};
});
最后,如果您要静态设置它,这也应该有效:
<div gorilla template-base-url="/templates"></div>