Javascript 具有动态templateUrl方法的嵌套指令失败

Javascript 具有动态templateUrl方法的嵌套指令失败,javascript,angularjs,angularjs-directive,Javascript,Angularjs,Angularjs Directive,TL;医生: 在指令的templateUrl方法中使用attr值时,在使用子指令时未对attr进行插值。最终结果是文本{{attrName}}/something.html 完整故事: 我有一个外部指令,包括内部指令。诀窍是,这些内部指令也是可以在不知道父对象的情况下独立存在的项 规则很简单: 如果一个项目是单独使用的,那么它的配置必须通过属性传递给它 如果某个项由其父项包含,则必须通过父项属性将其配置传递给该项 我无法将完整的组合HTML写入index.HTML。它必须在飞行中装载。这就是规

TL;医生: 在指令的templateUrl方法中使用attr值时,在使用子指令时未对attr进行插值。最终结果是文本
{{attrName}}/something.html

完整故事: 我有一个外部指令,包括内部指令。诀窍是,这些内部指令也是可以在不知道父对象的情况下独立存在的项

规则很简单:

  • 如果一个项目是单独使用的,那么它的配置必须通过属性传递给它
  • 如果某个项由其父项包含,则必须通过父项属性将其配置传递给该项
  • 我无法将完整的组合HTML写入index.HTML。它必须在飞行中装载。这就是规则。但是,这样做可以解决问题
  • URL必须是动态的,并且父级必须能够在不依赖范围继承的情况下传递此信息-父级可能不存在
  • 第三方网站无法告诉我使用JS指向何处。他们唯一的工具是类似index.HTML中的HTML。属性配置很好
Index.html:

<div zoo feeding-time="8am" template-base="/templates"></div>
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}
是从
templateurl
方法使用的。我只能追溯到当gorilla的
templateUrl
方法使用
attrs.templateBaseUrl
时,
attrs.templateBaseUrl
还没有插值

因此,
gorilla.link()
是在对
{{{templateBaseUrl}}
进行插值和kaboom之前运行的。404位于“{templateBaseUrl}}/gorilla.html”

我怎样才能避免这种情况

$compile/tpload?p0=%7B%7BtemplateBaseUrl%7D%7D%2Fgorilla.html

我在每个项目所依赖的提供者中都有这个baseUrl,但它与这个简化版本具有相同的效果。这一定是解析顺序问题。

为什么?
您的方法失败,因为
templateUrl
函数必须在控制器的“编译”阶段之前运行(如果没有模板,则无法编译模板)。对于嵌套指令,首先运行所有编译函数,然后运行链接函数。我发现下面的图表对于使用嵌套指令时的“什么运行时”很有用,这是一本非常好的读物

记住这一点,可以清楚地看到,当您的gorilla指令编译时,zoo的link函数没有运行,这意味着范围值甚至没有被设置,更不用说插入属性了

如何避免 看起来您必须自己获取并编译模板。可以使用angular来确保正确缓存模板。我们可以通过只使用范围中的值来避免担心插值是否发生(我使用了一个隔离范围,因为它使事情变得不那么模棱两可,通常是更好的做法,但是如果需要,可以使用范围继承)

免责声明:以下代码是在未运行的情况下编写的,肯定会包含打字错误和错误!希望你能明白其中的逻辑

子指令代码: 请注意,pre-link函数的第一行基本上检查是否存在使用您传递的名称设置的范围变量,如果没有,则假定您为其提供了url字符串(因此使用属性值)。这可能不是最好的方法——我可能会尝试使用两种不同的属性,但这取决于您

重要的是(再次查阅图表!),您的父指令(zoo)必须在其pre-link函数中设置模板基的值,否则当子指令的link函数运行时,该值将
未定义

(简化)母指令: 您可以使用类似于此处的child指令,或者使用您最初的方法。此代码经过简化,给出了在预链接期间如何设置
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
      }
    }
  };
});
角度模块(“应用程序”) .指令(“zoo”,函数(){ 返回{ 限制:“A”, 模板:“”, 链接:{ 前置:功能(范围、要素、属性){ //确保它设置在这里! scope.tplBaseUrl=“/templates”; }, 职位:职能(范围、要素、属性){ //链接逻辑 } } }; });
最后,如果您要静态设置它,这也应该起作用:

<div gorilla template-base-url="/templates"></div> 


templateUrl
函数在插入属性值之前以及在拥有“范围”之前运行。您应该使用内部指令的link函数来构造模板,或者使用
ng include
动态添加模板路径。此外,您应该使用
require
获取父级的控制器实例,并以这种方式获取模板值。有趣的问题-我在回答这个问题时学到了一些东西-如果我的答案有任何不清楚的地方,请告诉我,重要的是,如果它有效!我摆弄着要求,但大猩猩不需要动物园。有可能他们只是疯了似的到处游荡,所以不需要需求。相反,我使用的是由任何人设置的工厂值顺序(如果有),如果没有工厂值,则使用attr。我将尝试此方法。我在用compile执行一个前后策略,但它没有范围,所以我撞到了墙。我不知道林克也有预科。
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";
            }
        };
    }]);
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.
      }
    }
  };
});
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>