次のように、ng-include
およびng-repeat
を使用してアプリの複数の場所で使用するコントローラーを作成しました。
<div
ng-repeat="item in items"
ng-include="'item.html'"
ng-controller="ItemController"
></div>
コントローラー/テンプレートでは、item
値が存在することを期待していますが、この考えに基づいて全体が構築されています。しかし、今では、ng-repeat
なしで、わずかに異なる方法でコントローラーを使用する必要がありますが、item
を渡すことができる必要があります。 ng-init
を見て、次のように、必要なことができると思いました。
<div
ng-init="item = leftItem"
ng-include="'item.html'"
ng-controller="ItemController"
></div>
<div
ng-init="item = rightItem"
ng-include="'item.html'"
ng-controller="ItemController"
></div>
しかし、それは機能していないようです。このような単一のインスタンスでスコープの変数を渡す方法はありますか?
編集:これより上のコントローラーは、次のようなleftItem
およびrightItem
の値を読み込んでいます:
.controller('MainController', function($scope, ItemModel) {
ItemModel.loadItems()
.then(function(items) {
$scope.$apply(function() {
$scope.leftItem = items.left;
$scope.rightItem = items.right;
});
});
});
私はそれをディレクティブに書き直し、スコープの必要な値を
scope: {
item: '='
}
これを行うには、onload
が提供するngInclude
属性を使用できます。
<div ng-include="'item.html'"
ng-controller="ItemController"
onload="item = rightItem">
</div>
編集
親スコープで次のようなことを試してください:
$scope.dataHolder = {};
次に、非同期データを受信したら、データをdataHolder
に保存します。
$scope.dataHolder.leftItem = items.leftItem;
$scope.dataHolder.rightItem = items.rightItem;
ng-include
がテンプレートをロードすると、親のプロパティを継承する子スコープが作成されます。したがって、$scope.dataHolder
は、この子スコープで(最初は空のオブジェクトとして)定義されます。ただし、非同期データを受信した場合、空のオブジェクトへの参照には新しく受信したデータが含まれている必要があります。
パーティーに遅れたが、愚かなディレクティブを実装せずにこれを達成するための小さなangular 'hack'がある。
Ng-includeを使用するすべての場所にコントローラーのスコープ(ng-ifなど)を拡張する組み込みディレクティブを追加すると、実際には、含まれているすべてのスコープの変数名を分離できます。
そう:
<div ng-include="'item.html'"
ng-if="true"
onload="item = rightItem">
</div>
<div ng-include="'item.html'"
ng-if="true"
onload="item = leftItem">
</div>
その後、異なるアイテムを使用して、テンプレートitem.htmlをアイテム変数に複数回バインドできます。
問題は、各オンロード命令で消去されるアイテム変数への参照を1つだけ保持するコントローラースコープでアイテムが変化し続けることでした。
現在のスコープを拡張するディレクティブを導入すると、すべてのng-includeのスコープを分離できます。結果として、アイテム参照は保持され、すべての拡張スコープで一意になります。
@Taninの答えが大好きです。 so一度に多くの問題を非常にエレガントな方法で解決します。 Coffeescriptを知らない私のようなあなたのために、javascriptがあります...
注:私が理解するにはあまりにも新しい理由のため、このコードでは、テンプレート名を二重引用符で囲むng-includeの要件ではなく、テンプレート名onceを引用符で囲む必要があります。 <div ng-include-template="template-name.html" ... >
の代わりに<div ng-include-template="'template-name.html'" ... >
.directive('ngIncludeTemplate', function() {
return {
templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },
restrict: 'A',
scope: {
'ngIncludeVariables': '&'
},
link: function(scope, elem, attrs) {
var vars = scope.ngIncludeVariables();
Object.keys(vars).forEach(function(key) {
scope[key] = vars[key];
});
}
}
})
Onloadを使用することは、グローバルスコープを散らかすため、きれいなソリューションではありません。もっと複雑なものがあると、失敗し始めます。
ng-includeはグローバルスコープにアクセスできるため、それほど再利用できません。ちょっと変です。
上記は正しくありません。ng-ifonloadはグローバルスコープを無駄にしません
また、すべての状況に対して特定のディレクティブを記述したくありません。
Ng-includeの代わりに汎用ディレクティブを作成すると、よりクリーンなソリューションになります。
理想的な使用法は次のとおりです。
<div ng-include-template="'item.html'" ng-include-variables="{ item: 'whatever' }"></div>
<div ng-include-template="'item.html'" ng-include-variables="{ item: variableWorksToo }"></div>
ディレクティブは次のとおりです。
.directive(
'ngIncludeTemplate'
() ->
{
templateUrl: (elem, attrs) -> attrs.ngIncludeTemplate
restrict: 'A'
scope: {
'ngIncludeVariables': '&'
}
link: (scope, elem, attrs) ->
vars = scope.ngIncludeVariables()
for key, value of vars
scope[key] = value
}
)
ディレクティブがグローバルスコープを使用していないことがわかります。代わりに、ng-include-variablesからオブジェクトを読み取り、それらのメンバーを独自のローカルスコープに追加します。
これがあなたの望むものであることを願っています。クリーンで汎用的です。
これにはng-initの方が良いと思います。
<div ng-include='myFile.html' ng-init="myObject = myCtrl.myObject; myOtherObject=myCtrl.myOtherObject"/>
上記は、<div ng-include-template=... ng-include-variables="{ id: var.id }">
などの第2レベルの属性では機能しません。 var.id
に注意してください。
更新されたディレクティブ(見苦しいが機能します):
.directive('ngIncludeTemplate', function() {
return {
templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },
restrict: 'A',
scope: {
'ngIncludeVariables': '&'
},
link: function(scope, elem, attrs) {
var cache = scope.ngIncludeVariables();
Object.keys(cache).forEach(function(key) {
scope[key] = cache[key];
});
scope.$watch(
function() {
var val = scope.ngIncludeVariables();
if (angular.equals(val, cache)) {
return cache;
}
cache = val;
return val;
},
function(newValue, oldValue) {
if (!angular.equals(newValue, oldValue)) {
Object.keys(newValue).forEach(function(key) {
scope[key] = newValue[key];
});
}
}
);
}
};
});
MikeとTaninの回答の明らかな更新-インラインテンプレートを次のように使用している場合:
<script type="text/ng-template" id="partial">{{variable}}</script>
<div ng-include-template="'partial'" ng-include-variables="{variable: variable}"></div>
次に、ディレクティブngIncludeTemplateで、
templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },
と
template: function(elem, attrs) { return document.getElementById(attrs.ngIncludeTemplate.split("'")[1]).innerHTML },