ディレクティブからコントローラーにAngularJSスコープ変数を渡す最も簡単な方法は?


99

ディレクティブからコントローラーにAngularJSスコープ変数を渡す最も簡単な方法は何ですか?私が見たすべての例は非常に複雑に見えますが、ディレクティブからコントローラーにアクセスして、スコープ変数の1つを設定する方法はありませんか?


参照stackoverflow.com/questions/17900201/...より洞察力のために
Saksham

回答:


150

2014/8/25に編集: ここで私が分岐しました。

@anvarikに感謝します。

こちらがJSFiddleです。これを分岐した場所を忘れました。しかし、これは=と@の違いを示す良い例です

<div ng-controller="MyCtrl">
    <h2>Parent Scope</h2>
    <input ng-model="foo"> <i>// Update to see how parent scope interacts with component scope</i>    
    <br><br>
    <!-- attribute-foo binds to a DOM attribute which is always
    a string. That is why we are wrapping it in curly braces so
    that it can be interpolated. -->
    <my-component attribute-foo="{{foo}}" binding-foo="foo"
        isolated-expression-foo="updateFoo(newFoo)" >
        <h2>Attribute</h2>
        <div>
            <strong>get:</strong> {{isolatedAttributeFoo}}
        </div>
        <div>
            <strong>set:</strong> <input ng-model="isolatedAttributeFoo">
            <i>// This does not update the parent scope.</i>
        </div>
        <h2>Binding</h2>
        <div>
            <strong>get:</strong> {{isolatedBindingFoo}}
        </div>
        <div>
            <strong>set:</strong> <input ng-model="isolatedBindingFoo">
            <i>// This does update the parent scope.</i>
        </div>
        <h2>Expression</h2>    
        <div>
            <input ng-model="isolatedFoo">
            <button class="btn" ng-click="isolatedExpressionFoo({newFoo:isolatedFoo})">Submit</button>
            <i>// And this calls a function on the parent scope.</i>
        </div>
    </my-component>
</div>
var myModule = angular.module('myModule', [])
    .directive('myComponent', function () {
        return {
            restrict:'E',
            scope:{
                /* NOTE: Normally I would set my attributes and bindings
                to be the same name but I wanted to delineate between
                parent and isolated scope. */                
                isolatedAttributeFoo:'@attributeFoo',
                isolatedBindingFoo:'=bindingFoo',
                isolatedExpressionFoo:'&'
            }        
        };
    })
    .controller('MyCtrl', ['$scope', function ($scope) {
        $scope.foo = 'Hello!';
        $scope.updateFoo = function (newFoo) {
            $scope.foo = newFoo;
        }
    }]);

29
素晴らしい説明と例!なぜドキュメントがとても複雑なのでしょうか?それとも、私はそれほど優れたプログラマではないのですか?
kshep92 2013年

2
このフィドルは同様に機能することに注意してください。ただし、角度バージョンをより新しいバージョン(つまり、1.0.1から1.2.1に)に変更すると、機能しなくなります。構文について何かが変更されている必要があります。
eremzeit 14

2
最後に、意味のある明確な例。2時間の頭痛は10秒で解決しました。
Chris

4
メソッドが値をコントローラからディレクティブにではなく、コントローラからディレクティブに渡す方法を説明しているときに、どうしてみんながこの回答に投票するのですか?
Tiberiu C. 2015

2
isolatedBindingFoo: '= bindingFoo'は、ディレクティブからコントローラーにデータを渡すことができます。またはサービスを利用できます。誰かに反対票を投じる前に、理解していない場合は最初に質問してください。
maxisam 2015年

70

角度が変数を評価するまで待ちます

私はこれをいじくり回していましたが"="、スコープで定義された変数を使っても機能しませんでした。状況に応じて、次の3つの解決策があります。


ソリューション#1


変数がディレクティブに渡されたときに、変数がまだ角度で評価されていないことがわかりまし。これは、アクセスしてテンプレートで使用できることを意味しますが、評価されるのを待つまでは、リンクまたはアプリコントローラー関数内では使用できません。

あなたの場合は、変数が変化している、またはリクエストによって取得され、あなたが使用する必要があります$observe$watch

app.directive('yourDirective', function () {
    return {
        restrict: 'A',
        // NB: no isolated scope!!
        link: function (scope, element, attrs) {
            // observe changes in attribute - could also be scope.$watch
            attrs.$observe('yourDirective', function (value) {
                if (value) {
                    console.log(value);
                    // pass value to app controller
                    scope.variable = value;
                }
            });
        },
        // the variable is available in directive controller,
        // and can be fetched as done in link function
        controller: ['$scope', '$element', '$attrs',
            function ($scope, $element, $attrs) {
                // observe changes in attribute - could also be scope.$watch
                $attrs.$observe('yourDirective', function (value) {
                    if (value) {
                        console.log(value);
                        // pass value to app controller
                        $scope.variable = value;
                    }
                });
            }
        ]
    };
})
.controller('MyCtrl', ['$scope', function ($scope) {
    // variable passed to app controller
    $scope.$watch('variable', function (value) {
        if (value) {
            console.log(value);
        }
    });
}]);

そして、これがhtmlです(かっこを忘れないでください!):

<div ng-controller="MyCtrl">
    <div your-directive="{{ someObject.someVariable }}"></div>
    <!-- use ng-bind in stead of {{ }}, when you can to avoids FOUC -->
    <div ng-bind="variable"></div>
</div>

関数"="を使用している場合は、変数をスコープ内に設定しないでください$observe。また、オブジェクトを文字列として渡すことがわかったので、オブジェクトを渡す場合は、ソリューション#2またはscope.$watch(attrs.yourDirective, fn)(または、変数が変化しない場合は#3)を使用します。


ソリューション#2


あなたの場合は、変数は、例えば、他のコントローラで作成されたが、ちょうど角度アプリのコントローラに送信する前にそれを評価されるまで待つ必要があり、我々は使用することができる$timeoutまで待つこと$applyを実行しています。また、を使用$emitして親スコープのアプリコントローラーに送信する必要があります(ディレクティブのスコープが分離されているため)。

app.directive('yourDirective', ['$timeout', function ($timeout) {
    return {
        restrict: 'A',
        // NB: isolated scope!!
        scope: {
            yourDirective: '='
        },
        link: function (scope, element, attrs) {
            // wait until after $apply
            $timeout(function(){
                console.log(scope.yourDirective);
                // use scope.$emit to pass it to controller
                scope.$emit('notification', scope.yourDirective);
            });
        },
        // the variable is available in directive controller,
        // and can be fetched as done in link function
        controller: [ '$scope', function ($scope) {
            // wait until after $apply
            $timeout(function(){
                console.log($scope.yourDirective);
                // use $scope.$emit to pass it to controller
                $scope.$emit('notification', scope.yourDirective);
            });
        }]
    };
}])
.controller('MyCtrl', ['$scope', function ($scope) {
    // variable passed to app controller
    $scope.$on('notification', function (evt, value) {
        console.log(value);
        $scope.variable = value;
    });
}]);

そして、これがhtmlです(括弧なし!):

<div ng-controller="MyCtrl">
    <div your-directive="someObject.someVariable"></div>
    <!-- use ng-bind in stead of {{ }}, when you can to avoids FOUC -->
    <div ng-bind="variable"></div>
</div>

ソリューション#3


あなたの場合は、変数が変更されていないと、あなたの指示でそれを評価する必要があり、あなたが使用できる$eval機能を:

app.directive('yourDirective', function () {
    return {
        restrict: 'A',
        // NB: no isolated scope!!
        link: function (scope, element, attrs) {
            // executes the expression on the current scope returning the result
            // and adds it to the scope
            scope.variable = scope.$eval(attrs.yourDirective);
            console.log(scope.variable);

        },
        // the variable is available in directive controller,
        // and can be fetched as done in link function
        controller: ['$scope', '$element', '$attrs',
            function ($scope, $element, $attrs) {
                // executes the expression on the current scope returning the result
                // and adds it to the scope
                scope.variable = scope.$eval($attrs.yourDirective);
                console.log($scope.variable);
            }
         ]
    };
})
.controller('MyCtrl', ['$scope', function ($scope) {
    // variable passed to app controller
    $scope.$watch('variable', function (value) {
        if (value) {
            console.log(value);
        }
    });
}]);

そして、これがhtmlです(かっこを忘れないでください!):

<div ng-controller="MyCtrl">
    <div your-directive="{{ someObject.someVariable }}"></div>
    <!-- use ng-bind instead of {{ }}, when you can to avoids FOUC -->
    <div ng-bind="variable"></div>
</div>

また、この答えを見てくださいhttps : //stackoverflow.com/a/12372494/1008519

FOUC(スタイルのないコンテンツのフラッシュ)の問題のリファレンス:http ://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED

興味のある人のために:ここに角度のライフサイクルに関する記事があります


1
ng-if="someObject.someVariable"ディレクティブ(またはディレクティブを属性として持つ要素)の単純なもので十分な場合があります-ディレクティブsomeObject.someVariableは、定義された後ではじめます。
marapet 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.