एंगुलरजेएस स्कोप वैरिएबल को डायरेक्टिव से कंट्रोलर पास करने का सबसे आसान तरीका है?


99

डायरेक्टर से कंट्रोलर तक AngularJS स्कोप वैरिएबल पास करने का सबसे आसान तरीका क्या है? मेरे द्वारा देखे गए सभी उदाहरण इतने जटिल प्रतीत होते हैं, क्या ऐसा कोई तरीका नहीं है जिससे मैं किसी निर्देश से किसी नियंत्रक तक पहुँच सकता हूँ, और इसके किसी एक चर को सेट कर सकता हूँ?


अधिक जानकारी के लिए देखें stackoverflow.com/questions/17900201/…
सकाम

जवाबों:


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

2
ध्यान दें कि यह फ़िडल इन के रूप में काम करता है, लेकिन यदि आप कोणीय संस्करण को और अधिक हाल के एक में बदलते हैं (यानी 1.0.1 से 1.2.1 तक), तो यह अब काम नहीं करेगा। वाक्यविन्यास के बारे में कुछ बदल गया होगा।
इरेमेजिट

2
अंत में एक स्पष्ट उदाहरण जो समझ में आता है। 2 सेकंड का सिरदर्द 10 सेकंड में हल हो गया।
क्रिस

4
हर कोई कैसे इस जवाब को वोट देता है जबकि विधि बताती है कि नियंत्रक से एक निर्देश पर एक मान कैसे पारित किया जाए और एक नियंत्रक से एक निर्देश से नहीं?
टिबेरिउ सी।

2
आइसोलेशनबाइंडफू: '= बाइंडिंगफू' डेटा को डायरेक्टिव से कंट्रोलर तक पहुंचा सकता है। या आप सेवा का उपयोग कर सकते हैं। इससे पहले कि आप किसी ऐसे व्यक्ति को वोट दें, जिसका स्वागत करने के लिए आप सबसे पहले पूछें, अगर आपको समझ में नहीं आता है।
मैक्सिमम

70

प्रतीक्षा करें जब तक कोणीय ने चर का मूल्यांकन नहीं किया

मेरे पास इसके साथ बहुत सी फ़िदालिंग थी, और इसे "="दायरे में परिभाषित चर के साथ भी काम करने के लिए नहीं मिला । यहां आपकी स्थिति के आधार पर तीन समाधान दिए गए हैं।


समाधान # 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.