2017-03-08 7 views
2

ng-repeat内でディレクティブをコンパイルするときにスコープに関する問題を解決するのに役立つ人はいますか?ng-repeat内でカスタムディレクティブをコンパイルできない

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

カスタムディレクティブinput-by-typeは、変数の型に基づいて、適切な<input><div>を置き換えることができます - ng-repeat内で使用されるまで、これが正常に動作します。

plnkrの例で分かるように、指示はng-repeatの中で使用されるまで、期待通りに機能します。

私は手動でinput-by-typeディレクティブをコンパイルするinputs[0]を参照する場合、それだけで正常に動作します:

<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


実際の出力:を省略することにより

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

Actual

答えて

2

ポストリンク機能はelementattrsパラメータが欠落していますとattrsのパラメータの場合、postLink関数はクロージャを作成し、compile関数のelementattrs引数を使用しました。 $ compileサービスは適切な引数を指定してpostLink関数を呼び出していましたが、無視され、代わりにコンパイル段階のバージョンが使用されていました。

これは、要素を新しいDOM要素に追加するために要素を複製するため、ng-repeatの問題を引き起こします。

+0

は、私は、彼らが位相に応じて異なる可能性があることをポストリンク引数を知っていました。ありがとうございました。 – oodavid

0

@ georgeawgの回答は正しいですが、私は解決策で以下に概要を説明する2番目の問題に遭遇しました。

問題:ngModelが期待どおりに動作しませんでした(/$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

関連する問題