私は次のように含まれているテンプレートにコントローラを動的に割り当てようとしています:
<section ng-repeat="panel in panels">
<div ng-include="'path/to/file.html'" ng-controller="{{panel}}"></div>
</section>
しかしAngularは{{panel}}
が未定義であると不平を言います。
{{panel}}
が定義されていないと思いますまだ(テンプレート内で{{panel}}
をエコー出力できるため)。
私は、ng-controller
をng-controller="template.ctrlr"
のような変数に等しく設定する多くの例を見てきました。しかし、重複した並行ループを作成しないと、{{panel}}
が必要なときにng-controller
の値を使用できるようにする方法を理解できません。
追伸また、テンプレートにng-controller="{{panel}}"
を設定しようとしましたが(それまでに解決されているはずです)、ダイスはありませんでした。
あなたの問題は、ng-controllerがコントローラの名前の文字列だけでなく、コントローラ自体を指す必要があることです。
そのため、$ scope.sidepanelsを、コントローラへのポインタを持つ配列として定義したい場合があります。たとえば、次のようになります。
$scope.sidepanels = [Alerts, Subscriptions];
これがjsフィドルの実際の例です http://jsfiddle.net/ADukg/1559/
ただし、ngRepeatでコントローラーをセットアップする必要がある場合、私はこのすべての状況を非常に奇妙に感じます。
テンプレートでコントローラーを動的に設定するには、コントローラーに関連付けられたconstructor関数への参照を用意すると便利です。コントローラーのコンストラクター関数は、Angularの モジュールAPI のcontroller()
メソッドに渡す関数です。
ngController
ディレクティブに渡された文字列が登録済みコントローラーの名前ではない場合、ngController
は文字列を評価対象の式として扱うため、これが役立ちます現在のスコープ。このスコープ式は、コントローラーコンストラクターに評価される必要があります。
たとえば、Angularとすると、テンプレートで次のようになります。
_ng-controller="myController"
_
myController
という名前のコントローラーが登録されていない場合、Angularは現在含まれているコントローラーの_$scope.myController
_を調べます。このキーがスコープに存在し、対応するvalueはコントローラーコンストラクターであり、コントローラーが使用されます。
これは、パラメーター値の説明の ngController
ドキュメントで言及されています:「グローバルにアクセスできるコンストラクター関数の名前または現在のスコープでコンストラクター関数に評価される式」。 Angularソースコード内のコードコメントは、これをより詳しく説明します ここでは_src/ng/controller.js
_ です。
デフォルトでは、Angularでは、コントローラーに関連付けられたコンストラクターに簡単にアクセスできません。これは、Angularのcontroller()
メソッドを使用してコントローラーを登録すると、 モジュールAPI 、プライベート変数で渡したコンストラクタを非表示にします。これは $ ControllerProviderソースコード で確認できます(このコードのcontrollers
変数_$ControllerProvider
_にプライベートな変数です。)
この問題に対する私の解決策は、コントローラーを登録するためのregisterController
と呼ばれる汎用ヘルパーサービスを作成することです。このサービスは、コントローラーの登録時に、コントローラーとの両方のコントローラーコンストラクターを公開します。これにより、コントローラーを通常の方法と動的な方法の両方で使用できます。
これは、これを行うregisterController
サービス用に私が作成したコードです。
_var appServices = angular.module('app.services', []);
// Define a registerController service that creates a new controller
// in the usual way. In addition, the service registers the
// controller's constructor as a service. This allows the controller
// to be set dynamically within a template.
appServices.config(['$controllerProvider', '$injector', '$provide',
function ($controllerProvider, $injector, $provide) {
$provide.factory('registerController',
function registerControllerFactory() {
// Params:
// constructor: controller constructor function, optionally
// in the annotated array form.
return function registerController(name, constructor) {
// Register the controller constructor as a service.
$provide.factory(name + 'Factory', function () {
return constructor;
});
// Register the controller itself.
$controllerProvider.register(name, constructor);
};
});
}]);
_
以下は、サービスを使用してコントローラーを登録する例です。
_appServices.run(['registerController',
function (registerController) {
registerController('testCtrl', ['$scope',
function testCtrl($scope) {
$scope.foo = 'bar';
}]);
}]);
_
上記のコードは、testCtrl
という名前でコントローラーを登録し、コントローラーのコンストラクターをtestCtrlFactory
というサービスとして公開します。
これで、通常の方法でテンプレートでコントローラーを使用できます-
_ng-controller="testCtrl"
_
または動的に-
_ng-controller="templateController"
_
後者が機能するには、現在のスコープに次のものが必要です。
_$scope.templateController = testCtrlFactory
_
もう1つの方法は、ng-repeatを使用せずに、それらをコンパイルして存在させるディレクティブです。
[〜#〜] html [〜#〜]
<mysections></mysections>
ディレクティブ
angular.module('app.directives', [])
.directive('mysections', ['$compile', function(compile){
return {
restrict: 'E',
link: function(scope, element, attrs) {
for(var i=0; i<panels.length; i++) {
var template = '<section><div ng-include="path/to/file.html" ng-controller="'+panels[i]+'"></div></section>';
var cTemplate = compile(template)(scope);
element.append(cTemplate);
}
}
}
}]);
あなたがこのようにコントローラーを定義しているので、あなたはこの問題を抱えていると思います(私が慣れているように):
app.controller('ControllerX', function() {
// your controller implementation
});
その場合、ControllerX
への参照を単純に使用することはできません。コントローラーの実装(またはそれを呼び出したい場合は 'Class')がグローバルスコープにないためです(代わりにアプリケーションに保存されます$controllerProvider
)。
コントローラー参照を動的に割り当てる(または手動で作成する)代わりに、テンプレートを使用することをお勧めします。
コントローラ
var app = angular.module('app', []);
app.controller('Ctrl', function($scope, $controller) {
$scope.panels = [{template: 'panel1.html'}, {template: 'panel2.html'}];
});
app.controller("Panel1Ctrl", function($scope) {
$scope.id = 1;
});
app.controller("Panel2Ctrl", function($scope) {
$scope.id = 2;
});
テンプレート(モック)
<!-- panel1.html -->
<script type="text/ng-template" id="panel1.html">
<div ng-controller="Panel1Ctrl">
Content of panel {{id}}
</div>
</script>
<!-- panel2.html -->
<script type="text/ng-template" id="panel2.html">
<div ng-controller="Panel2Ctrl">
Content of panel {{id}}
</div>
</script>
ビュー
<div ng-controller="Ctrl">
<div ng-repeat="panel in panels">
<div ng-include src="panel.template"></div>
</div>
</div>
jsFiddle: http://jsfiddle.net/Xn4H8/