2015-01-20 69 views
4

TL; DR: 在僞指令的templateUrl方法中使用attr值時,attr在使用子僞指令時未被插值。最終結果是文字{{attrName}}/something.html帶動態templateUrl方法失敗的嵌套僞指令

全文: 我有一個外部指令,其中包括內部指令。訣竅是,這些內部指令也是可以在沒有父母知識的情況下自己生活的項目。

的規則很簡單:

  • 如果一個項目是單獨使用,它的配置必須在它通過將屬性傳遞。
  • 如果項目包含在其父項中,則必須通過父項屬性將其配置傳遞給它
  • 我無法將完整的組合HTML寫入index.html。它必須在飛行中加載。他們的規則。但是,這樣做可以解決問題。
  • 該URL必須是動態的,並且父級必須能夠傳遞此信息而不依賴於範圍繼承 - 父級可能不在此處。
  • 第三方網站無法告訴我在哪裏指出這些使用JS。他們唯一的工具就像index.html中的HTML一樣。屬性配置很好。

的Index.html:

<div zoo feeding-time="8am" template-base="/templates"></div> 

OR - index.html的也可能是:大猩猩可以顯式地指定ATTR值,因爲它不是繼承

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

動物園.html - 它將自己的配置傳遞給大猩猩

<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"; 
      } 
     }; 
    }]); 

這工作。有時。有時,從tempateUrl方法中使用字面{{templateBaseUrl}}。我只能看到,當attrs.templateBaseUrl被大猩猩的templateUrl方法使用時,attrs.templateBaseUrl它尚未被插值。

因此,gorilla.link()在插入{{templateBaseUrl}}和kaboom之前運行。 404 {at {{templateBaseUrl}}/gorilla.html「

我該如何避免這種情況?

https://docs.angularjs.org/error/ $ compile/tpload?p0 =%7B%7BtemplateBaseUrl%7D%7D%2Fgorilla。html

我有這個baseUrl東西在每個項目依賴的提供者,但它具有與此簡化版本相同的效果。它必須是解析順序問題。

+0

'templateUrl'函數運行的屬性值進行插值之前,你必須「範圍」之前。您應該使用inner指令的鏈接函數來構造模板或使用'ng-include'並動態添加模板路徑。此外,您應該使用'require'來獲取父級的控制器實例,並以這種方式獲取模板值。 – 2015-01-20 22:38:28

+0

有趣的問題 - 當我回答這個問題時,我學到了一些東西 - 讓我知道如果我的答案留下任何不清楚的東西,並且重要的是,如果它有效的話! – 2015-01-20 23:44:30

+0

我擺弄的要求,但大猩猩不需要動物園。他們可能只是在瘋狂地漫遊,所以不需要。相反,我使用由任何人設置的工廠值順序,如果有的話,attr如果沒有工廠值 – oooyaya 2015-01-21 03:13:11

回答

4

爲什麼?

你的方法失敗了,因爲templateUrl函數必須在控制器的'編譯'階段之前運行(如果你還沒有編譯模板,你不能編譯模板)。使用嵌套指令,所有的編譯函數首先運行,然後是鏈接函數。我發現下圖在使用嵌套指令時可以作爲'什麼時候運行'的參考 - 它來自相當於in depth article的主題 - 一個很好的閱讀。

http://www.jvandemo.com/content/images/2014/Aug/cycle-2.png

考慮到這一點,很明顯地看到,當你的大猩猩指令編譯,動物園的鏈接功能還沒有運行,這意味着甚至還沒有被設置的範圍值,讓單獨插入到屬性中。

如何避免

它看起來像你將不得不自己獲取和編譯模板。您可以利用角色的$templateRequest確保模板正確緩存。我們可以避免擔心插值是否僅僅使用範圍內的值而發生(我使用了隔離範圍,因爲它使事情變得更加模糊,並且通常是更好的練習,但是如果您希望只使用範圍繼承)。

免責聲明:下面的代碼已經寫入而沒有運行它,並且肯定會包含錯別字和錯誤!希望你會看到雖然邏輯...

兒童指令代碼:

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字符串(所以使用屬性值)。這可能不是最好的辦法 - 我會試圖使用兩個不同的屬性,但這取決於你。

重要的(再次參考圖!),你(動物園)指令必須設置在其預鏈接功能模板庫的價值,否則當孩子指令的鏈接功能運行值將是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> 
+0

我會試試這個。我在編譯時採用了前後策略,但它沒有範圍,所以我只是一堵牆。我也不知道鏈接是否有預先。 – oooyaya 2015-01-21 03:08:21

+0

我忘了跟進了。這個伎倆。 – oooyaya 2015-03-04 19:56:55