2017-03-08 83 views
2

任何人都可以幫助我解決在ng-repeat內編譯指令時的範圍界定問題嗎?自定義指令無法在ng-repeat內編譯

https://plnkr.co/edit/y6gfpe01x3ya8zZ5QQpt?p=preview

自定義指令input-by-type可以取代<div>基於變量類型適當<input> - 直到ng-repeat內使用能正常工作。

正如您在plnkr示例中所看到的,該指令按預期工作,直至在ng-repeat內使用。

如果我手動引用inputs[0]編譯input-by-type指令,它工作得很好:

<label> 
    {{ inputs[0].name }} 
    <div input-by-type="{{ inputs[0].type }}" name="myInputA" ng-model="data.A" ng-required="true"></div> 
</label> 

然而,那一刻我在ng-repeat塊把這個包,編譯失敗,一些意想不到的輸出:

<label ng-repeat="input in inputs"> 
    {{ input.name }} 
    <div input-by-type="{{ input.type }}" name="myInput{{ $index }}" ng-model="data[input.id]" ng-required="true"></div> 
</label> 

預期輸出:

Expected


實際輸出:

Actual

回答

2

的postLink功能缺失elementattrs參數:

app.directive('inputByType', ['$compile', '$interpolate', function($compile, $interpolate){ 
    return { 
     restrict: 'A', // [attribute] 
     require: '^ngModel', 
     scope: true, 
     // terminal: true, 
     compile: function(element, attrs, transclude){ 
      var inputs = { 
       text: '<input type="text" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="...">', 
       email: '<input type="email" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="[email protected]">', 
       number: '<input type="number" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="###">', 
       // image upload (redacted) 
       // file upload (redacted) 
       // date picker (redacted) 
       // color picker (redacted) 
       // boolean (redacted) 
      }; 
      //return function(scope){ 
      //USE postLink element, attrs 
      return function postLinkFn(scope, element, attrs) { 
       var type = $interpolate(attrs.inputByType)(scope); // Convert input-by-type="{{ some.type }}" into a useable value 
       var html = inputs[type] || inputs.text; 
       var e = $compile(html)(scope); 
       element.replaceWith(e); 
       console.log(type, html, element, e); 
      }; 
     }, 
    }; 
}]); 

通過省略elementattrs參數,postLink函數創建一個閉包並使用compile函數的參數elementattrs。即使$ compile服務使用正確的參數調用postLink函數,它們也被忽略,而是使用編譯階段版本。

這會導致ng-repeat出現問題,因爲它會克隆元素以將其附加到新的DOM元素。

+0

我知道的postLink參數但是它並沒有醒悟過來了,他們可以根據相位不同。謝謝。 – oodavid

0

@ georgeawg的答案是正確的,但是我遇到了第二個問題,我將在下面概述一個解決方案。

問題:ngModel不會按預期行事($pristine/$dirty等屬性將不可用,也不會傳播到容器formCtrl)。

爲了解決這個問題,我跟着這個答案的建議:https://stackoverflow.com/a/21687744/1122851和改變了postLink被編譯的元素,像這樣的方式:

var type = $interpolate(attrs.inputByType)(scope); 
var html = inputs[type] || inputs.text; 
var template = angular.element(html); 
element.replaceWith(template); 
$compile(template)(scope); 

我才明白,require: 'ngModel'scope: trueterminal: true沒有無論如何,它們都是我各種測試中的遺物。最終代碼:

app.directive('inputByType', ['$compile', '$interpolate', function($compile, $interpolate){ 
    return { 
     restrict: 'A', // [attribute] 
     compile: function(element, attrs, transclude){ 
      var inputs = { 
       text: '<input type="text" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="...">', 
       email: '<input type="email" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="[email protected]">', 
       number: '<input type="number" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="###">', 
       // image upload (redacted) 
       // file upload (redacted) 
       // date picker (redacted) 
       // color picker (redacted) 
       // boolean (redacted) 
      }; 
      return function postLinkFn(scope, element, attrs) { 
       var type = $interpolate(attrs.inputByType)(scope); // Convert input-by-type="{{ some.type }}" into a useable value 
       var html = inputs[type] || inputs.text; 
       var template = angular.element(html); 
       element.replaceWith(template); 
       $compile(template)(scope); 
      }; 
     }, 
    }; 
}]); 

演示:https://plnkr.co/edit/ZB5wlTKr0g5pXkRTRmas?p=preview