web-dev-qa-db-ja.com

AngularJSでコントローラを別のコントローラにインジェクトする方法

私は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

私は他のコントローラの中でコントローラを使用しようとさえしているべきですか、それとも私はこれをサービスにするべきですか?

94
Scottie

あなたの意図が他のコンポーネントの既にインスタンス化されたコントローラを手に入れることであり、あなたがコンポーネント/ディレクティブベースのアプローチに従うなら、あなたは常にある階層に従う他のコンポーネントからのコントローラ(コンポーネントのインスタンス)を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を渡します。

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



古い答え:

あなたは $controller serviceをインジェクトして他のコントローラ内のコントローラをインスタンス化する必要があります。しかし、これは設計上の問題につながる可能性があることに注意してください。 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.
}]);

どの場合でも、メソッドはコントローラインスタンスではなく$scopeにアタッチされているため、TestCtrl1.myMethod()を呼び出すことはできません。

あなたがコントローラを共有している場合、それはそれを行うことをお勧め常にします: -

.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があなたのビューモデルで、後者の場合はコントローラインスタンスそのものです。

128
PSL

私があなたが尋ねるべきである質問がコントローラにサービスを注入する方法であることを提案したいです。細いコントローラを使ったファットサービスは経験則であり、コントローラを使って(ビジネスロジックを使って)サービス/ファクトリをビューに接着することもできます。

たとえば、値を表示するビジネスロジックをコントローラで保持している場合、アプリのユーザーがブラウザの戻るボタンをクリックすると、2つのページで状態が失われます。

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

app.factory('methodFactory', function () {
    return { myMethod: function () {
            console.log("methodFactory - myMethod");
    };
};

app.controller('TestCtrl1', ['$scope', 'methodFactory', function ($scope,methodFactory) {  //Comma was missing here.Now it is corrected.
    $scope.mymethod1 = methodFactory.myMethod();
}]);

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

これは二つのコントローラに注入されたファクトリの実用的な デモです

また、サービス/ファクトリに関するこのチュートリアルを 読んでおくことをお勧めします。

33
cheekybastard

JSであなたのコントローラをインポート/インジェクトする必要はありません。あなたはちょうどあなたのHTMLを通してあなたのコントローラ/入れ子になったコントローラを注入することができます。それは私のために働きました。好きです:

<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>
13
chetanpawar