23

次のように、含まれているテンプレートにコントローラーを動的に割り当てようとしています。

<section ng-repeat="panel in panels">
    <div ng-include="'path/to/file.html'" ng-controller="{{panel}}"></div>
</section>

しかし、Angular はそれ{{panel}}が未定義であると不平を言っています。

まだ{{panel}}定義されていないと思います (テンプレート内でエコーアウトできるため)。{{panel}}

ng-controllerso: のように変数に等しい値を設定する例をたくさん見てきましたng-controller="template.ctrlr"。しかし、重複する並行ループを作成しないと、必要{{panel}}なときに使用可能な値を取得する方法がわかりません。ng-controller

PS私もng-controller="{{panel}}"自分のテンプレートで設定しようとしましたが(それまでに解決されているに違いないと思います)、サイコロはありませんでした。

4

5 に答える 5

16

問題は、コントローラーの名前を含む文字列だけでなく、 ng-controller がコントローラー自体を指す必要があることです。

$scope.sidepanels をコントローラへのポインタを持つ配列として定義したいかもしれません。たとえば、次のようになります。

$scope.sidepanels = [Alerts, Subscriptions];

js fiddle http://jsfiddle.net/ADukg/1559/の実際の例を次に示します。

ただし、ngRepeat でコントローラーをセットアップしたい場合、このような状況はすべて非常に奇妙です。

于 2012-12-19T04:18:38.370 に答える
6

テンプレートでコントローラーを動的に設定するには、コントローラーに関連付けられたコンストラクター関数への参照があると役立ちます。コントローラーのコンストラクター関数は、controller()Angular のモジュール APIのメソッドに渡す関数です。

ngControllerディレクティブに渡された文字列が登録済みコントローラーの名前ではない場合、文字列をngController現在のスコープで評価される式として扱うため、これが役立ちます。このスコープ式は、コントローラーコンストラクターに評価される必要があります。

たとえば、Angular がテンプレートで次のものに遭遇したとします。

ng-controller="myController"

その名前のコントローラーmyControllerが登録されていない場合、Angular は$scope.myController現在含まれているコントローラーを参照します。このキーがスコープ内に存在し、対応する値がコントローラーコンストラクターの場合、コントローラーが使用されます。

これはngController、パラメーター値の説明でドキュメントに記載されています。「グローバルにアクセス可能なコンストラクター関数の名前、または現在のスコープでコンストラクター関数に評価される式。」Angular ソース コードのコード コメントは、この詳細についてここでsrc/ng/controller.js説明しています。

デフォルトでは、Angular はコントローラーに関連付けられたコンストラクターへのアクセスを容易にしません。これはcontroller()、Angular のモジュール 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
于 2014-07-08T07:52:04.793 に答える
5

この問題が発生しているのは、コントローラーを次のように定義しているためだと思います(私が慣れているように)。

app.controller('ControllerX', function() {
    // your controller implementation        
});

その場合、ControllerXコントローラーの実装(または、それを呼び出す場合は「クラス」)がグローバルスコープにない(代わりにアプリケーションに格納される)ため、への参照を単純に使用することはできません$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/

于 2012-12-19T15:12:03.270 に答える
5

別の方法は、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);
                }
            }
        }
    }]);
于 2014-04-22T10:24:15.000 に答える