2015-03-03 77 views
4

因此,替換:在不久的將來,將從AngularJS中刪除true。我明白爲什麼,但我認爲在AngularJS中開發的某些場景沒有它可以得到很好的支持。替代替代:對於angularJS指令爲true

我想創建一個按鈕組件,看起來像這樣:

<button ng-click="doSomething()" important-model="outerCtrl.theModel"> 
    important text 
</button> 

即從屬性開始,例如,像這樣:

<div my-button-component> 
</div> 

現在使用替代我得到了我想要,但由於它已被棄用,我想避免使用它,所以我認爲也許我可以這樣做:

<button my-button-component ng-click="doSomething()" important-model="outerCtrl.theModel"> 
</button> 

讓指令在裏面插入'重要文本'。

這個解決方案很奇怪,因爲雖然ng-click可以訪問指令範圍,並且可以像預期的那樣工作(就好像它在指令模板中一樣),但是我的組件是一個按鈕並且是可點擊的,否則應該在我的組件內部定義,而不是在我選擇使用它的模板中。

另一種選擇是隻有一個div包裝所有這一點,由於前端約束,這是不可接受的。

最後一個選擇是接受我無法使用指令控制根元素的類型或屬性,並且在程序中應用點擊偵聽器和任何其他行爲(例如ng-class)。這對我來說似乎不是一個好的解決方案,但它可能是迄今爲止最好的解決方案。

這不是我第一次覺得你對指令的根元素有多少控制有些問題,我是否在想這個錯誤?

回答

6

首先,我不認爲替換:在不久的將來,真正被刪除。它已被棄用,但在任何角度1.X版本中擺脫它將是一個突破性的改變,所以我認爲你沒事,直到發佈Angular 2.0。 Angular 2.0將打破更多,所以我不會太擔心如何讓現有的應用程序工作,而不需要更換:true。很可能2.0會具有某種等效的功能,但將現有的應用程序遷移到2.0可能不是您想要做的事情。

然而,假設回答你的問題:

取代:真正做了兩兩件事:

1)替換元素與指令模板的DOM。

2)它將DOM中元素的屬性與指令模板合併。

(2)實際上是該特徵的非平凡部分,它周圍的邊緣情況是Angular團隊想要擺脫它的原因。

舉例來說,如果你的元素是:

<div some-directive ng-click="doSomething()"><div> 

而且someDirective有一個模板:

<div ng-click="doSomethingInDirective()"></div> 

你已經更換了節點之後的優先級? replace:true的邏輯當前會做出這些決定併爲您提供一切。

如果出於某種原因將其替換爲:真正從1.X中刪除(它不會),那麼你會怎麼做?

答案是,你將不得不手工做的替換:真正做現在,這(簡體)是:

1)獲取的原始元素的屬性

2)合併的原始元素與屬性指令模板,跟蹤不是指令和屬性的屬性,並且跟蹤每個指令的聲明位置(在原始元素或模板中)。

3)通過編譯合併的屬性指令和指令模板指令來編譯指令模板。

4)將作爲原始元素一部分的合併屬性指令鏈接到$ parent作用域,並將所有其他指令鏈接到指令作用域。鏈接指令該指令範圍

4A)如果必要的話(transclude執行transclusion:true和模板包括NG-transclude)

5)替換爲完全掛鉤指令模板原始元素。

這裏是從GitHub的相關代碼:

if (directive.replace) { 
      replaceDirective = directive; 
      if (jqLiteIsTextNode(directiveValue)) { 
       $template = []; 
      } else { 
       $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue))); 
      } 
      compileNode = $template[0]; 

      if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { 
       throw $compileMinErr('tplrt', 
        "Template for directive '{0}' must have exactly one root element. {1}", 
        directiveName, ''); 
      } 

      replaceWith(jqCollection, $compileNode, compileNode); 

      var newTemplateAttrs = {$attr: {}}; 

      // combine directives from the original node and from the template: 
      // - take the array of directives for this element 
      // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) 
      // - collect directives from the template and sort them by priority 
      // - combine directives as: processed + template + unprocessed 
      var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); 
      var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); 

      if (newIsolateScopeDirective) { 
       markDirectivesAsIsolate(templateDirectives); 
      } 
      directives = directives.concat(templateDirectives).concat(unprocessedDirectives); 
      mergeTemplateAttributes(templateAttrs, newTemplateAttrs); 

我不會出去,很快寫自己,任何時候的版本。任何需要替換的代碼:true也需要Angular 1.X,所以它會被支持。當你準備用Angular 2.0寫一個新的應用程序時,會有另一種(希望更好)的方式來做到這一點。

2

聽起來和你一樣,在這種情況下應該使用指令元素,而不是指令屬性。

按照該guidance from the Angular docs,使用元素,當你想創建可重用的組件,而當你要增加的東西的行爲屬性:

使用,當你創建一個組件,它是一個元素控制模板。常見的情況是當您爲模板的某些部分創建特定於域的語言時。在使用新功能裝飾現有元素時使用屬性。

當你使用一個指令元素沒有replace: true

<my-button-component example-attr="example"></my-button-component> 

將輸出:

<my-button-component example-attr="example"> 
    <button ng-click="doSomething()" important-model="outerCtrl.theModel"> 
     important text 
    </button> 
</my-button-component> 

<my-button-component>標籤沒有意​​義的瀏覽器,這樣就不會影響到文檔流或造型。

在該指令,你還是吐出相同<button> HTML,你仍然有機會獲得通過像example-attr屬性傳入的值,所以是不是真的在所有replace: truereplace: false多大區別。

+0

「標籤對瀏覽器沒有任何意義」......但不幸的是它對其他指令有意義。例如,標籤內的任何內容都不再可用於Angular的表單驗證。所以有一個堅實的用例來「替換」。 transclude是否提供相同的功能? – 2015-07-09 01:44:23

+0

「..對瀏覽器沒有意義..」,取決於你所指的意義。我遇到了指令元素纏繞標籤並因此使用替換的問題。如果你在之外有任何非表元素(table或thead,tbody等)的元素,那麼你的行不能正確呈現。 – 2016-01-17 01:11:38

+0

它也不會做屬性合併,這對於我製作包裝文件輸入的組件時非常重要。 – Thayne 2016-04-29 23:44:39