1. ホーム
  2. angularjs

[解決済み] AngularJSでコントローラを別のコントローラにインジェクトする方法

2023-01-20 11:44:59

質問

私はAngularの初心者で、どのようにすればいいのか考えています。

AngularJSを使用して、どのように別のコントローラ内で使用されるコントローラを注入することができますか?

私は以下のスニペットを持っています。

var app = angular.module("testApp", ['']);

app.controller('TestCtrl1', ['$scope', function ($scope) {
    $scope.myMethod = function () {
        console.log("TestCtrl1 - myMethod");
    }
}]);

app.controller('TestCtrl2', ['$scope', 'TestCtrl1', function ($scope, TestCtrl1) {
    TestCtrl1.myMethod();
}]);

これを実行すると、エラーが発生します。

Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1
http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1

コントローラを別のコントローラの中で使おうとしても、これはサービスにした方がいいのでしょうか?

どのように解決するのですか?

既にインスタンス化された別のコンポーネントのコントローラを取得することを意図している場合、そしてコンポーネント/ディレクティブベースのアプローチに従っている場合は、常に require のコントローラ (コンポーネントのインスタンス) を、 特定の階層に従った別のコンポーネントから取得することができます。

例えば

//some container component that provides a wizard and transcludes the page components displayed in a wizard
myModule.component('wizardContainer', {
  ...,
  controller : function WizardController() {
    this.disableNext = function() { 
      //disable next step... some implementation to disable the next button hosted by the wizard
    }
  },
  ...
});

//some child component
myModule.component('onboardingStep', {
 ...,
 controller : function OnboadingStepController(){

    this.$onInit = function() {
      //.... you can access this.container.disableNext() function
    }

    this.onChange = function(val) {
      //..say some value has been changed and it is not valid i do not want wizard to enable next button so i call container's disable method i.e
      if(notIsValid(val)){
        this.container.disableNext();
      }
    }
 },
 ...,
 require : {
    container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy.
 },
 ...
});

さて、これらのコンポーネントの使い方は次のようなものでしょう。

<wizard-container ....>
<!--some stuff-->
...
<!-- some where there is this page that displays initial step via child component -->

<on-boarding-step ...>
 <!--- some stuff-->
</on-boarding-step>
...
<!--some stuff-->
</wizard-container>

を設定する方法はたくさんあります。 を要求する .

(接頭辞なし) - 現在の要素で必要なコントローラを探します。見つからない場合はエラーを投げる。

? - 必要なコントローラの場所を特定しようとするか、見つからない場合はリンクfnにnullを渡します。

^ - 要素とその親を検索することによって、必要なコントローラを見つけます。見つからなければエラーを投げる。

^ - 要素の親を検索して、必要なコントローラを見つけます。見つからなければエラーを投げます。

?^ - 要素とその親を検索して必要なコントローラを見つけようとするか、見つからない場合はリンク fn に null を渡します。

?^ - 要素の親を検索して必要なコントローラを見つけようとするか、見つからなければ link fn に null を渡します。



古い回答です。

以下のように $controller サービスを注入して、コントローラを別のコントローラ内にインスタンス化する必要があります。しかし、これはデザイン上の問題を引き起こす可能性があることに注意してください。Single Responsibilityに従った再利用可能なサービスを作成し、 必要に応じてコントローラの中に注入することもできます。

例です。

app.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
   var testCtrl1ViewModel = $scope.$new(); //You need to supply a scope while instantiating.
   //Provide the scope, you can also do $scope.$new(true) in order to create an isolated scope.
   //In this case it is the child scope of this scope.
   $controller('TestCtrl1',{$scope : testCtrl1ViewModel });
   testCtrl1ViewModel.myMethod(); //And call the method on the newScope.
}]);

いずれにせよ TestCtrl1.myMethod() にメソッドをアタッチしているので $scope にメソッドをアタッチしているからです。

もしコントローラを共有しているのであれば、常にそうする方が良いでしょう。

.controller('TestCtrl1', ['$log', function ($log) {
    this.myMethod = function () {
        $log.debug("TestCtrl1 - myMethod");
    }
}]);

と消費しながら行う。

.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
     var testCtrl1ViewModel = $controller('TestCtrl1');
     testCtrl1ViewModel.myMethod();
}]);

最初のケースでは、本当に $scope はビューモデルであり、2番目の場合はコントローラのインスタンスそのものです。