2015-11-04 96 views
0

我想創建一個名爲availableTo的指令,它可以根據某些消息在兩個不同的模板之間切換。例如,如果該字段是帶ng-model指令的input,則首先需要使用<span>標記將其更改爲只讀。到目前爲止,我的代碼可以切換視圖爲只讀,但我似乎無法切換回input角度指令:動態切換兩個模板

var directive = { 
     restrict: 'A', 
     require: '?ngModel', 
     link: linkerFn, 
     replace: true 
    }; 

function linkerFn(scope, element, attrs, ngModelCtrl) { 

     var clonedElement = angular.copy(element); 
     var preOuterHTML = clonedElement[0].outerHTML; //this can save the <input> field html code 

     scope.$on('mode_changed', function() { 
      var curUserRole = userservices.getUserRole(); 

      if (attrs.availableTo == curUserRole) { 
       var e = $compile(preOuterHTML)(scope); 
       element.replaceWith(e); 
      } else { 
       var template = '<span>' + ngModelCtrl.$viewValue + '</span>'; 
       var e = $compile(template)(scope); 
       element.replaceWith(e); 
      } 

     }); //scope.$on 
    } //linkerFn 

對於input場:

<input name="test1" class="form-control" ng-model="name" placeholder="Name 1" available-to="ADMIN"/> 

我還注意到,一旦我更改上面else塊中的模板,重新渲染元素,並且preOuterHTML不再包含原始元素html。這似乎是我不可能完成的任務,但我想聽聽一些專家意見。謝謝

回答

3

element.replaceWith(e);不這樣做。在Angular中,如果您發現自己試圖直接修改DOM,您從定義上來說是錯誤的。你得坐下來讓Angular做這項工作。

如果你需要替換一個指令的整個模板,一個相當直接的方法是使用ng-include和一個範圍變量,該範圍變量包含所需的條件templateUrl,例如,

var directive = { 
    // ... 
    template: '<div ng-include="myTemplateUrl"></div>', 
    link: function(scope, el) { 
    if (/* whatever */) { 
     scope.myTemplateUrl="templates/foo.html"; 
    } else { 
     //...etc 
    } 
    }, 
}; 

(這確實一個額外的DOM節點添加到樹上,但是這通常是無害的。)

這聽起來像你的情況,你可能不需要走那麼遠,雖然;您的模板中的簡單ng-if可能足以在您的只讀<span><input>之間進行交換。

+0

_「如果您發現自己試圖直接修改DOM,則您在定義上做錯了」_ - 所以您真的建議Angular本身做錯了嗎?你指的是誰的定義? – zeroflagL

+0

@zeroflagL我認爲該陳述的重點是* only * angular應該修改DOM。在99%的時間裏,人們使用'element'方法,因爲他們不知道正確的方式來構建應用程序,這樣角度可以代替。答案爲這個用例提供了一個更好的方法。 – Claies

+0

@丹尼爾貝克,非常感謝您的解答。因爲我試圖使指令儘可能通用,所以我想我需要爲所有可能的輸入字段創建一個模板,例如'input','select','checkbox'。在Angular中似乎沒有直接緩存原始元素模板的方法。 – TonyGW