angularJS:親スコープで子スコープ関数を呼び出す方法


95

親スコープから子スコープで定義されたメソッドを呼び出すにはどうすればよいですか?

function ParentCntl() {
    // I want to call the $scope.get here
}

function ChildCntl($scope) {
    $scope.get = function() {
        return "LOL";    
    }
}

http://jsfiddle.net/wUPdW/


2
最善の策は、サービスを定義し、そのサービスを両方のコントローラーに注入することです。またはルートスコープを使用します。
tymeJV 2013

回答:


145

$broadcast親から子まで使用できます。

function ParentCntl($scope) {

    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$parent.msg = $scope.get();            
    });

    $scope.get = function(){
        return "LOL";    
    }
}

作業フィドル:http : //jsfiddle.net/wUPdW/2/

更新:結合度が低く、テストしやすい別のバージョンがあります。

function ParentCntl($scope) {
    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }

    $scope.$on('pingBack', function(e,data) {  
        $scope.msg = data;        
    });
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$emit("pingBack", $scope.get());        
    });

    $scope.get = function(){
        return "LOL";    
    }
}

フィドル:http : //jsfiddle.net/uypo360u/


それはいいね!あなたがいない場合でも、発信者の範囲がどこにあるか(I平均で知っているもの(たい)$scope.$parentまたは中$scope.$parent.$parentなど、)?ああ、はい:paramsにコールバックを渡します!:)
user2173353 14

@ user2173353あなたは正しいです。$emit子供から親へのもう1つの方法があります。私は私の答えを更新するための時間だと思う...
Cherniv

この場合は子コントローラーであるグローバルリスナーを呼び出すことをお勧めしますか?アンチパターンで、後でテストするのは難しいですか?インジェクションやスムスを使うべきではないでしょうか?
calmbird 2014

@calmbird、それぞれを注意深く使用する必要があります。それは確かです。同じような場合にサービスを使用することを好む人もいます。とにかく、私はよりエレガントなバージョンを追加しました(迷惑なしで$parent
Cherniv 14

9
このアプローチはよりクリーンです。でコールバックを渡す$broadcastと、pingBack完全に排除できます。
最高級の

34

別の解決策を提案させてください:

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


app.controller("ParentCntl", function($scope) {
    $scope.obj = {};
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

より少ないコードとプロトタイプ継承の使用。

プランク


誰かがこのアプローチが上記のイベント駆動型アプローチよりも優れているかどうかを説明できますか?子コントローラー付きのマルチLVL階層がある場合はどうなりますか?同じ関数名が定義されているコントローラーがない限り、obj.getが子コントローラー内の子コントローラー内で定義されている場合、これは機能しますか?前もって感謝します。
ZvKa

1
私が言ったことを完全に真実ではないものに訂正させてください。あなたが言ったことは正しいです:スコープ継承は一方向のみに適用されます...子->親。ここで実際に起こっていることは、子スコープで$ scope.getを定義すると、「get」は子スコープでのみ定義されることです(プリミティブ定義と呼ばれることもあります)。しかし、$ scope.obj.getを定義すると、子スコープは、上位の親スコープで定義されているobjを探します。
Canttouchit 2015

3
子供に独自の分離スコープがある場合、これはどのように機能しますか?
ディネシュ2015

2
問題は分離スコープを参照することではありませんでしたが、分離スコープがある場合は分離スコープバインディングを使用できます。イモ、放送は少し厄介です。
Canttouchit 2015

2
テンプレートではなく親のコントローラーから子コントローラーの関数にアクセスする必要がある場合、この例は可能ではないと思います。この例は、テンプレートの双方向バインディングのためにのみ$scope.obj.get()機能します。これは、有効な関数になるまでポーリングを続けると想定しています。
danyim 2016年

11

子供の初期化時に、子供の機能を親に登録します。テンプレートを明確にするために、「as」表記を使用しました。

テンプレート

<div ng-controller="ParentCntl as p">
  <div ng-controller="ChildCntl as c" ng-init="p.init(c.get)"></div>
</div>

コントローラー

...
function ParentCntl() {
  var p = this;
  p.init = function(fnToRegister) {
    p.childGet = fnToRegister;
  };
 // call p.childGet when you want
}

function ChildCntl() {
  var c = this;
  c.get = function() {
    return "LOL";    
  };
}

「しかし」、あなたは言う、「ng-init この方法で使用することは想定されていません!」。ええ、そうですが

  1. そのドキュメントはなぜそうでないのかを説明していない、そして
  2. ドキュメント作成者が考えられるすべてのユースケースを検討したとは思いません。

これは良い使い方だと思います。私に反対票を投じる場合は、理由をコメントしてください!:)

コンポーネントをよりモジュール化するため、このアプローチが気に入っています。唯一のバインディングはテンプレートにあり、それは

  • 子コントローラーは、その機能を追加するオブジェクトについて何も知る必要はありません(@canttouchitの回答のように)
  • 親コントロールは、get関数を持つ他の子コントロールと一緒に使用できます
  • ブロードキャストは必要ありません。イベントの名前空間を厳密に制御しない限り、大きなアプリでは非常に醜くなります。

このアプローチは、ディレクティブでモジュール化するというTeroのアイデアにさらに近づきます(彼のモジュール化された例でcontestantsは、親から「子」ディレクティブにテンプレートが渡されることに注意してください)。

実際、別の解決策はChildCntl、をディレクティブとして実装することを検討し、&バインディングを使用してinitメソッドを登録することです。


1
私はこれが古い投稿であることを知っていますが、子が破棄された後も親が子への参照を保持できるため、これは悪い考えのようです。
エイミーブランケンシップ2016年

これは、イベントをブロードキャストするよりもはるかにクリーンなソリューションです。完璧ではありませんが、優れています。クリーンアップは確かに問題ですが。
mcv 2018年

-1

子オブジェクトを作ることができます。

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


app.controller("ParentCntl", function($scope) {
    $scope.child= {};
    $scope.get = function(){
      return $scope.child.get(); // you can call it. it will return 'LOL'
    }
   // or  you can call it directly like $scope.child.get() once it loaded.
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

ここで子供はgetメソッドの宛先を証明しています。

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