コントローラーをAngularJSの別のコントローラーに挿入するにはどうすればよいですか?


97

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

別のコントローラーの内部でコントローラーを使用しようとしているか、これをサービスにする必要がありますか?


2
コントローラを相互に注入することはできません。はい、TestCtrl1代わりにサービスに変更する必要があります。
Sly_cardinal 2014

まさに、サービスを利用する
Miguel Mota 2014

3
ビューにバインドするコントローラーのプロパティを更新する必要がある場合はどうなりますか?このプロパティは、別のコントローラーで発生するイベントの影響を受けます。
Ankit Tanna

回答:


129

別のコンポーネントのすでにインスタンス化されたコントローラーを取得することが目的であり、コンポーネント/ディレクティブベースのアプローチに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>

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

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

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

^-要素とその親を検索して、必要なコントローラーを見つけます。見つからない場合はエラーをスローします。

^^-要素の親を検索して、必要なコントローラーを見つけます。見つからない場合はエラーをスローします。

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

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



古い答え:

$controller別のコントローラー内にコントローラーをインスタンス化するには、サービスを注入する必要があります。ただし、これにより設計上の問題が発生する可能性があることに注意してください。常に単一の責任に従う再利用可能なサービスを作成し、必要に応じてコントローラーに挿入することができます。

例:

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はビューモデルであり、後者の場合はコントローラーインスタンス自体です。


4
そしてそれは、コントローラーによって提供される機能に依存します。コンポーネント間で共有する必要があるビューモデルのように作成する場合は問題ありませんが、サービスプロバイダーの機能が多い場合は、サービスを作成するだけです。 。
PSL 2014

する必要var testCtrl1ViewModel = $scope.$new();がありvar testCtrl1ViewModel = $rootScope.$new();ますか?参照してください。docs.angularjs.org/guide/controller @PSL
leonsPAPA

上記の例では、ディレクティブコントローラーのコンテナーにアクセスしていますが、これを機能させることができません。ディレクティブ自体のリンク関数の4番目のパラメーターを使用して、必要なコントローラーにアクセスできます。ただし、上記の例のように、ディレクティブコントローラーにバインドされていません。他に誰かがこの問題を抱えていますか?
Sammi

33

コントローラにサービスを注入する方法について質問することをお勧めします。細いコントローラーを使用したファットサービスは良い目安です。別名コントローラーを使用して、サービス/ファクトリー(ビジネスロジックを含む)をビューに接着します。

コントローラーはルートの変更時にガベージコレクションを取得するため、たとえば、コントローラーを使用して値をレンダリングするビジネスロジックを保持している場合、アプリのユーザーがブラウザーの戻るボタンをクリックすると、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();
}]);

これは、2つのコントローラーに注入された工場の動作デモです

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


13

JSにコントローラーをインポート/インジェクトする必要はありません。HTMLを介してコントローラー/ネストされたコントローラーを挿入するだけでかまいません。お気に入り :

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

2
true ...しかし、私はまだすべての一般的な要素をサービスに入れて、それぞれのコントローラーにサービスを注入する方が良いと感じています。
Neel

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

これは、TestCtrl2に独自のディレクティブがある私の場合に最もよく機能します。

var testCtrl2 = $controller('TestCtrl2')

これにより、scopeProviderインジェクションエラーというエラーが表示されます。

   var testCtrl1ViewModel = $scope.$new();
   $controller('TestCtrl1',{$scope : testCtrl1ViewModel });
   testCtrl1ViewModel.myMethod(); 

「TestCtrl1」にディレクティブがある場合、これは実際には機能しません。そのディレクティブは、実際にここで作成されたものとは異なるスコープを持っています。最終的に、「TestCtrl1」の2つのインスタンスができます。


-1

最良の解決策:-

angular.module("myapp").controller("frstCtrl",function($scope){$scope.name="Atul Singh";}).controller("secondCtrl",function($scope){angular.extend(this, $controller('frstCtrl', {$scope:$scope}));console.log($scope);})

//ここでは、実行せずに最初のコントローラー呼び出しを取得します


-1

$rootScopeこのように2番目のコントローラーから1番目のコントローラーの関数/メソッドを呼び出すために使用することもできます。

.controller('ctrl1', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl();
     //Your code here. 
})

.controller('ctrl2', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl = function() {
     //Your code here. 
}
})

1
反対票:これは単に悪いコーディングです。関数をグローバルにするだけです。これがコード化したい方法である場合は、Angularを完全にドロップすることをお勧めします...他のほとんどの回答で提案されているサービスを使用します。
HammerNL 2016年

これは推奨されません。$ rootScopeはコードを扱いにくくし、長期的に問題を引き起こします。
Harshit Pant 2018

-2

コーディングにはtypescriptを使用してください。それは、オブジェクト指向であり、厳密に型指定されており、コードの保守が簡単だからです...

typeciptの詳細については、ここをクリックしてください

Typescriptを使用して2つのコントローラー間でデータを共有するために作成した簡単な例を1つ示します...

module Demo {
//create only one module for single Applicaiton
angular.module('app', []);
//Create a searvie to share the data
export class CommonService {
    sharedData: any;
    constructor() {
        this.sharedData = "send this data to Controller";
    }
}
//add Service to module app
angular.module('app').service('CommonService', CommonService);

//Create One controller for one purpose
export class FirstController {
    dataInCtrl1: any;
    //Don't forget to inject service to access data from service
    static $inject = ['CommonService']
    constructor(private commonService: CommonService) { }
    public getDataFromService() {
        this.dataInCtrl1 = this.commonService.sharedData;
    }
}
//add controller to module app
angular.module('app').controller('FirstController', FirstController);
export class SecondController {
    dataInCtrl2: any;
    static $inject = ['CommonService']
    constructor(private commonService: CommonService) { }
    public getDataFromService() {
        this.dataInCtrl2 = this.commonService.sharedData;
    }
}
angular.module('app').controller('SecondController', SecondController);

}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.