2016-11-07 9 views
0

これは実際の問題の単純化されたバージョンですが、何が起こっているのか、どのように修正するのかを理解したいと思います。私はそれにバインドされているパラメータに異なるテンプレートを読み込まなければなりません。ビジュアルディレクティブダイナミックテンプレートがバインディングで機能しない

var app = angular.module('my_app', []) 
 
    .controller('controller', Controller) 
 
    .directive('dirTwo', DirTwo); 
 

 
function Controller() { 
 
    var este = this; 
 
    this.list = ["number", "text", "text"]; 
 
    this.change = function() { 
 
    this.list = this.list.reverse(); 
 
    } 
 
} 
 

 
function DirTwo() { 
 
    return { 
 
    restrict: 'E', 
 
    //template: ' Name: {{name}}{{type}}', 
 
    template: my_template, 
 
    scope: { 
 
     type: "=" 
 
    }, 
 
    link: function($scope) { 
 
     $scope.name = "Pepito"; 
 
     console.log("scope type: " + $scope.type); 
 
    } 
 
    } 
 
} 
 
var my_template = function(elem, attrs, $scope) { 
 
    console.log("template type: " + attrs.type); 
 
    switch (attrs.type) { 
 
    case 'number': 
 
     return '<a href="#">{{type}}</a>'; 
 
     break; 
 
    default: 
 
     return ' ---- ' 
 
     break; 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script> 
 
<div class="app" ng-app="my_app" ng-controller="controller as App"> 
 
    <p>{{App.list}} 
 
    <button ng-click="App.change()">Reverse</button> 
 
    </p> 
 
    <dir-two ng-repeat="item in App.list track by $index" type="item"></dir-two> 
 
</div>

テンプレート関数のログは、ワードitem代わりにnumber又はtextを印刷します。テンプレートを正しくロードするにはどうすれば修正できますか?

+0

'type {" {item}} "'を試しましたか? – GillesC

+0

@GillesC、試してみたところ、エラーはさらに大きくなりました!実際、バインディングはリンク関数では動作しますが、テンプレートでは動作しません。 – Vandervals

答えて

1

typeがスコープの値を取るコンパイル段階の前にテンプレート解決が行われるため、残念ながらtemplateを使用する方法はありません。スコープ値に基づいてディレクティブのテンプレートを変更するには、その値を確認し、ディレクティブ要素が変更されたときにそのディレクティブ要素を再コンパイルする必要があります。ディレクティブを新しいテンプレートで完全に再コンパイルしますが、同じスコープを使用します。これを1回行うことができます(つまり、$watchを付けずに)。

次のスニペットは、このソリューションを実装しています。

var app = angular.module('my_app', []) 
 
    .controller('controller', Controller) 
 
    .directive('dirTwo', DirTwo); 
 

 
function Controller() { 
 
    var este = this; 
 
    this.list = ["number", "text", "text"]; 
 
    this.change = function() { 
 
    this.list = this.list.reverse(); 
 
    } 
 
} 
 

 
function DirTwo($compile) { 
 
    return { 
 
    restrict: 'E', 
 
    template: '', 
 
    scope: { 
 
     type: "=" 
 
    }, 
 
    link: function(scope, element) { 
 
     
 
     var tmplScope; 
 
     
 
     scope.name = "Pepito"; 
 
     scope.$watch('type', function(type) { 
 

 
     if (tmplScope) tmplScope.$destroy(); 
 

 
     tmplScope = scope.$new(); 
 

 
     element.html(getTemplate(type)); 
 
     $compile(element.contents())(tmplScope); 
 
     }); 
 
    } 
 
    } 
 
} 
 
var getTemplate = function(type) { 
 

 
    switch (type) { 
 
    case 'number': 
 
     return '<a href="#">{{type}}</a>'; 
 
     break; 
 
    default: 
 
     return ' ---- ' 
 
     break; 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script> 
 
<div class="app" ng-app="my_app" ng-controller="controller as App"> 
 
    <p>{{App.list}} 
 
    <button ng-click="App.change()">Reverse</button> 
 
    </p> 
 
    <dir-two ng-repeat="item in App.list track by $index" type="item"></dir-two> 
 
</div>

UPDATE注:は、私はそれがコンパイルされるたびに新しい子スコープを作成しても、それが再コンパイルしますと、この子スコープを破壊するために、実際のコンパイルシステムを変更しました以前のものを破棄せずに再コンパイルするときに新しいwatchersを追加しないようにしてください。コメントのこの問題について警告した@georgeawgに感謝します。

+0

テンプレートを再コンパイルするとメモリリークが発生することに注意してください。それぞれの新しいテンプレートはスコープにウォッチャーを追加します。 – georgeawg

+1

@georgeawgあなたは正しいです!私はそれに気付かなかった。私はまずそれが一度コンパイルされると思ったので、全く問題にはなりません。しかし、再コンパイルすると、スコープは新しいウォッチャーを作成し、古いものを生き残らせていました。潜在的には、ある程度の再コンパイルでメモリリークが発生します。私たちのためにこれを指摘してくれてありがとう、良い観察。私は私の答えも更新しました。 –

関連する問題