AngularJS-子スコープへのアクセス


110

次のコントローラがある場合:

function parent($scope, service) {
    $scope.a = 'foo';

    $scope.save = function() {
        service.save({
            a:  $scope.a,
            b:  $scope.b
        });
    }
}

function child($scope) {
    $scope.b = 'bar';
}

parent読み上げる適切な方法bchild何ですか?で定義する必要がある場合、それが関連する何かを記述するプロパティbでありparent、そうでないことbを記述するプロパティであると仮定すると、意味的に正しくchildないparentでしょうか?

更新:それについてさらに考えると、複数の子がbそれを持っている場合parent、それbを取得するための競合が発生します。私の質問は残っていますb、からアクセスする適切な方法は何parentですか?


1
また、必ずこちらをお読みください:stackoverflow.com/questions/14049480 / ... angularJSのスコープと継承の非常に優れた詳細な概要。
Martijn 2013

回答:


162

AngularJSのスコープはプロトタイプの継承を使用します。子スコープでプロパティを検索すると、インタプリタは子からプロトタイプチェーンを検索し、プロパティが見つかるまで親まで続きます。

この問題に関するVojtaのコメントを確認してくださいhttps://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

簡単に言えば、親スコープから子スコープにアクセスすることはできません。

あなたのソリューション:

  1. 親のプロパティを定義し、子からそれらにアクセスします(上のリンクを読んでください)
  2. サービスを使用して状態を共有する
  3. イベントを介してデータを渡します。$emitルートスコープまでイベントを親に送信し、イベントを$broadcast下に送出します。これは、意味的に正しいものを維持するのに役立つ場合があります。

8
さらに、$ emitと$ broadcastの違いは、$ emitがキャンセル可能であり、$ broadcastが不可である点です。
Azri Jamil

おそらく子スコープを取得したい場所の1つは、ディレクティブを単体テストするときです。トランスクルードされたディレクティブがある場合、スコープは要素のコンパイルに使用されるスコープの子です。テスト用にコンパイルされたディレクティブのスコープにアクセスすることは困難です。
pmc 14

ありがとう。別のオプションとしてlocalStorage、のような依存関係がありngStorageます。
Akash 2016

81

jm-の答えがこのケースを処理する最良の方法ですが、将来の参照のために、スコープの$$ childHead、$$ childTail、$$ nextSibling、および$$ prevSiblingメンバーを使用して子スコープにアクセスすることが可能です。これらはドキュメント化されていないため、予告なしに変更される可能性がありますが、スコープを実際にトラバースする必要がある場合は存在します。

// get $$childHead first and then iterate that scope's $$nextSiblings
for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
    // cs is child scope
}

フィドル


49

あなたはこれを試すことができます:

$scope.child = {} //declare it in parent controller (scope)

次に、子コントローラー(スコープ)に次を追加します。

var parentScope = $scope.$parent;
parentScope.child = $scope;

これで、親は子のスコープにアクセスできます。


1
とてもクリーンで分かりやすい。これに追加するには、バインディングがないことを理解するだけなので、上記のように宣言すると、parentScope.childはその時点で子スコープを保持しています。これを解決するには、$ scope。$ watch(function(){parentScope.child = $ scope});を追加できます。そのため、すべてのダイジェストの後で、新しいスコープを親にプッシュします。親側で、htmlのビジュアルに子スコープのいずれかを使用している場合は、その子変数にウォッチを追加して、スコープを更新するように指示する必要があります。$ scope。$ watch( 'child'、function( ){$ scope。$ evalAsync();}); 。これが誰かの時間を節約することを願っています!
IfTrue

2
@IfTrue $ watch()は不要だと思います。これらはオブジェクトであり、参照によって渡されます。
スワニディ2015

2
@Swanidhi =私はあなたが何を意味しているのか知っているし、私もそう思っていたが、コメントを書いている時点で実験していたときはうまくいかなかった。これを行う価値があるので、これを行うことから、emitting / broadcastingに切り替えました。
IfTrue

1
タイプスクリプトでこれを行う方法
ATHER

私にとってベストアンサー!! JavaScriptで参照として扱われるオブジェクトの最良の例
Vikas Gautam

4

考えられる回避策の1つは、init関数を使用して、子コントローラーを親コントローラーに挿入することです。

可能な実装:

<div ng-controller="ParentController as parentCtrl">
   ...

    <div ng-controller="ChildController as childCtrl" 
         ng-init="ChildCtrl.init()">
       ...
    </div>
</div>

ChildControllerあなたがいる場所:

app.controller('ChildController',
    ['$scope', '$rootScope', function ($scope, $rootScope) {
    this.init = function() {
         $scope.parentCtrl.childCtrl = $scope.childCtrl;
         $scope.childCtrl.test = 'aaaa';
    };

}])

だから今ではParentControllerあなたが使うことができます:

app.controller('ParentController',
    ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {

    this.save = function() {
        service.save({
            a:  $scope.parentCtrl.ChildCtrl.test
        });
     };

}])

重要:
正しく機能するには、ディレクティブを使用し、htmlで行ったようにng-controller各コントローラーの名前を変更する必要がありますas

ヒント:処理中に
Chromeプラグインng-inspectorを使用します。ツリーを理解するのに役立ちます。


3

使用$ EMIT$放送を(上記のコメントでwalvが言及)

イベントを上方向に(子から親へ)起動するには

$scope.$emit('myTestEvent', 'Data to send');

下方向にイベントを起動するには(親から子へ)

$scope.$broadcast('myTestEvent', {
  someProp: 'Sending you some data'
});

そして最後に聞く

$scope.$on('myTestEvent', function (event, data) {
  console.log(data);
});

詳細:-https : //toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

楽しい :)


1

はい、子コントローラーの変数を親コントローラーの変数に割り当てることができます。これは可能な方法の1つです。

概要:以下のコードの主な目的は、子コントローラーの$ scope.variableを親コントローラーの$ scope.assignに割り当てることです

説明: 2つのコントローラーがあります。htmlでは、親コントローラーが子コントローラーを囲んでいることに注意してください。つまり、親コントローラーが子コントローラーの前に実行されます。したがって、最初にsetValue()が定義され、次にコントロールが子コントローラーに移動します。$ scope.variableは「子」として割り当てられます。次に、この子スコープは引数として親コントローラーの関数に渡され、$ scope.assignは値を「子」として取得します

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script type="text/javascript">
    var app = angular.module('myApp',[]);

    app.controller('child',function($scope){
        $scope.variable = "child";
        $scope.$parent.setValue($scope);
    });

    app.controller('parent',function($scope){
        $scope.setValue = function(childscope) {
            $scope.assign = childscope.variable;
        }
    });

</script>
<body ng-app="myApp">
 <div ng-controller="parent">
    <p>this is parent: {{assign}}</p>
    <div ng-controller="child">
        <p>this is {{variable}}</p>
    </div>
 </div>
</body>
</html>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.