AngularJS में अलग-अलग गुंजाइश के बिना एक निर्देश से नियंत्रक फ़ंक्शन को कॉल करें


95

मैं अलग-अलग दायरे का उपयोग किए बिना एक निर्देश के भीतर से पैरेंट स्कोप पर किसी फंक्शन को कॉल करने का तरीका नहीं खोज सकता। मुझे पता है कि अगर मैं अलग-अलग दायरे का उपयोग करता हूं, तो मैं अभिभावक के कार्यक्षेत्र में फ़ंक्शन का उपयोग करने के लिए अलग-थलग "&" का उपयोग कर सकता हूं, लेकिन आवश्यक नहीं होने पर अलग-अलग गुंजाइश का उपयोग करना। निम्नलिखित HTML पर विचार करें:

<button ng-hide="hideButton()" confirm="Are you sure?" confirm-action="doIt()">Do It</button>

इस सरल उदाहरण में, मैं एक जावास्क्रिप्ट पुष्टिकरण संवाद दिखाना चाहता हूं और केवल doIt () को कॉल करना चाहता हूं यदि वे पुष्टिकरण संवाद में "ओके" पर क्लिक करते हैं। यह एक अलग दायरे का उपयोग करके सरल है। निर्देश इस तरह दिखेगा:

.directive('confirm', function () {
    return {
        restrict: 'A',
        scope: {
            confirm: '@',
            confirmAction: '&'
        },
        link: function (scope, element, attrs) {
            element.bind('click', function (e) {
                if (confirm(scope.confirm)) {
                    scope.confirmAction();
                }
            });
        }
    };
})

लेकिन समस्या यह है, क्योंकि मैं अलग-अलग गुंजाइश का उपयोग कर रहा हूं, ऊपर के उदाहरण में एनजी-छिपाना अब माता-पिता के दायरे के खिलाफ निष्पादित नहीं होता है , बल्कि अलग-अलग दायरे में होता है (क्योंकि किसी भी निर्देश पर एक अलग-अलग गुंजाइश का उपयोग करने से उस तत्व पर सभी निर्देशों का कारण बनता है) पृथक स्कोप का उपयोग करें)। यहां उपरोक्त उदाहरण का एक jsFiddle है जहां एनजी-छिपाने काम नहीं कर रहा है। (ध्यान दें कि इस फ़ाइल में, जब आप इनपुट बॉक्स में "हां" टाइप करते हैं, तो बटन को छिपा देना चाहिए।)

विकल्प एक पृथक दायरे का उपयोग नहीं करना होगा , जो वास्तव में मैं वास्तव में यहां चाहता हूं क्योंकि इस निर्देश के दायरे को अलग करने की कोई आवश्यकता नहीं है। मेरे पास एक ही समस्या है, अगर मैं इसे अलग-थलग दायरे में पास नहीं करता तो मैं पैरेंट स्कोप पर एक विधि कैसे कहूं ?

यहाँ एक jsfiddle है जहां मैं अलग-अलग गुंजाइश का उपयोग नहीं कर रहा हूं और एनजी-छिपाना ठीक काम कर रहा है, लेकिन निश्चित रूप से, पुष्टिकरण () के लिए कॉल काम नहीं करता है, और मुझे नहीं पता कि यह कैसे काम करता है।

कृपया ध्यान दें, मैं वास्तव में जिस उत्तर की तलाश कर रहा हूं वह यह है कि एक अलग दायरे का उपयोग किए बिना बाहरी दायरे पर फ़ंक्शन को कैसे कॉल किया जाए। और मुझे इस पुष्टिकरण संवाद को दूसरे तरीके से बनाने में कोई दिलचस्पी नहीं है, क्योंकि इस सवाल का बिंदु यह पता लगाना है कि बाहरी दायरे में कॉल कैसे किया जाए और अभी भी माता-पिता के दायरे के खिलाफ अन्य निर्देश काम करने में सक्षम हैं।

वैकल्पिक रूप से, मुझे उन समाधानों के बारे में सुनने में दिलचस्पी होगी जो एक अलग दायरे का उपयोग करते हैं यदि अन्य निर्देश अभी भी मूल दायरे के खिलाफ काम करेंगे , लेकिन मुझे नहीं लगता कि यह संभव है।


पास करने वालों के लिए, डान वेहलिन ने एक बहुत अच्छा लेख लिखा है, जिसमें अलग-अलग गुंजाइश और फंक्शन पैरामीटर्स को समझाया गया है: weblogs.asp.net/dwahlin/…
tanguy_k

जवाबों:


117

चूंकि निर्देश केवल एक फ़ंक्शन कह रहा है (और किसी संपत्ति पर मूल्य निर्धारित करने की कोशिश नहीं कर रहा है), आप $ पार्सल (गैर-पृथक दायरे के साथ) के बजाय $ eval का उपयोग कर सकते हैं :

scope.$apply(function() {
    scope.$eval(attrs.confirmAction);
});

या बेहतर, बस $ लागू का उपयोग करें , जो $ eval होगा () गुंजाइश के खिलाफ अपने तर्क का उपयोग करें:

scope.$apply(attrs.confirmAction);

बेला


पता नहीं था, उसके लिए धन्यवाद। मैंने हमेशा सोचा है कि $ पारसी विधि थोड़ी बहुत चिंताजनक थी।
क्लार्क पैन

2
आप उस फ़ंक्शन पर पैरामीटर कैसे सेट करेंगे?
CMCDragonkai

2
@CMCDragonkai, यदि फ़ंक्शन में तर्क हैं, तो आप उन्हें HTML में निर्दिष्ट कर सकते हैं confirm-action="doIt(arg1)", और फिर अतिरिक्त scope.arg1कॉल करने से पहले सेट कर सकते हैं । हालाँकि, यह शायद $ parse का उपयोग करने के लिए क्लीनर होगा: stackoverflow.com/a/16200618/215945
Mark Rajcok

क्या स्कोप करना संभव नहीं है। $ eval (attrs.doIt ({arg1: 'blah'});?
CMCDragonkai

3
@CMCDragonkai, नहीं, scope.$eval(attrs.confirmAction({arg1: 'blah'})काम नहीं करेगा। आपको उस वाक्य रचना के साथ $ पार्स का उपयोग करने की आवश्यकता होगी।
मार्क राजकोक

17

आप AngularJS में $ parse सेवा का उपयोग करना चाहते हैं।

तो आपके उदाहरण के लिए:

.directive('confirm', function ($parse) {
    return {
        restrict: 'A',

        // Child scope, not isolated
        scope : true,
        link: function (scope, element, attrs) {
            element.bind('click', function (e) {
                if (confirm(attrs.confirm)) {
                    scope.$apply(function(){

                        // $parse returns a getter function to be 
                        // executed against an object
                        var fn = $parse(attrs.confirmAction);

                        // In our case, we want to execute the statement in 
                        // confirmAction i.e. 'doIt()' against the scope 
                        // which this directive is bound to, because the 
                        // scope is a child scope, not an isolated scope. 
                        // The prototypical inheritance of scopes will mean 
                        // that it will eventually find a 'doIt' function 
                        // bound against a parent's scope.
                        fn(scope, {$event : e});
                    });
                }
            });
        }
    };
});

$ पार्स का उपयोग करके संपत्ति सेट करने के लिए एक गोचा है, लेकिन जब आप इसके पास आते हैं तो मैं आपको उस पुल को पार करने देता हूं।


धन्यवाद, क्लार्क, यह वही है जो मैं देख रहा था। मैंने $ पार्स का उपयोग करने की कोशिश की थी, लेकिन यह मेरे लिए काम नहीं कर रहा था, इसलिए गुंजाइश पास करने में विफल रहा। यह पूर्ण है।
जिम कूपर

मुझे यह जानकर आश्चर्य हुआ कि यह समाधान भी बिना गुंजाइश के काम करता है: सच। मेरी समझ यह थी कि दायरा: सच्चा वह है जो निर्देशक के दायरे को मूल रूप से मूल दायरे से अलग करता है। किसी भी विचार क्यों यह अभी भी इसके बिना काम करता है?
जिम कूपर

2
कोई भी चाइल्ड स्कोप (डिलीट करना scope:true) काम नहीं करता क्योंकि डायरेक्शन बिल्कुल भी नया स्कोप नहीं बनाएगा, और इस प्रकार scopeआप जिस प्रॉपर्टी को linkफंक्शन में रेफर करते हैं वह पहले वाले 'पैरेंट' स्कोप की तरह ही स्कोप है।
क्लार्क पैन

$ लागू इस मामले के लिए पर्याप्त है (मेरा उत्तर देखें)।
मार्क राजकॉक

1
के लिए $ घटना क्या है?
CMCDragonkai

12

स्पष्ट रूप hideButtonसे मूल क्षेत्र पर कॉल करें ।

यहाँ की बेला है: http://jsfiddle.net/pXej2/5/

और यहाँ अद्यतन HTML है:

<div ng-app="myModule" ng-controller="myController">
    <input ng-model="showIt"></input>
    <button ng-hide="$parent.hideButton()" confirm="Are you sure?" confirm-action="doIt()">Do It</button>
</div>

एक काम के समाधान के लिए +1। मैंने वास्तव में $ माता-पिता का उपयोग करने की कोशिश की थी और जब यह काम नहीं किया था। आपके समाधान को देखने के बाद, मैंने एक करीब से देखा और यह पता चला कि मैं उन मापदंडों में $ माता-पिता को जोड़ने में असफल रहा था जो मैं गुजर रहा था (मेरी मूल पहेली में नहीं दिखाया गया था)। उदाहरण के लिए, अगर मैं hideButton () फ़ंक्शन में showIt पास करना चाहता था, तो मुझे $ parent.hideButton ($ parent.showIt) का उपयोग करने की आवश्यकता होगी और मुझे दूसरा $ माता-पिता याद आ रहा था। मैं क्लार्क के जवाब को स्वीकार करने जा रहा हूं, हालांकि, क्योंकि उस समाधान के लिए मेरे निर्देश के उपयोगकर्ता को यह जानने की आवश्यकता नहीं है कि उन्हें $ माता-पिता को जोड़ने की आवश्यकता है। अंतर्दृष्टि के लिए धन्यवाद!
जिम कूपर

1

मेरे पास एक ही समस्या है, अगर मैं इसे अलग-थलग दायरे में पास नहीं करता तो मैं पैरेंट स्कोप पर एक विधि कैसे कहूं?

यहाँ एक jsfiddle है जहां मैं अलग-अलग गुंजाइश का उपयोग नहीं कर रहा हूं और एनजी-छिपाना ठीक काम कर रहा है, लेकिन, निश्चित रूप से, पुष्टिकरण () के लिए कॉल काम नहीं करता है और मुझे नहीं पता कि यह कैसे काम करता है।

पहला छोटा बिंदु: इस मामले में बाहरी नियंत्रक का दायरा निर्देशक के दायरे का मूल क्षेत्र नहीं है; बाहरी नियंत्रक की गुंजाइश है निर्देश की गुंजाइश। दूसरे शब्दों में, निर्देश में उपयोग किए जाने वाले चर नाम को सीधे नियंत्रक के दायरे में देखा जाएगा।

अगला, लेखन इस बटन के attrs.confirmAction()कारण काम नहीं करता है attrs.confirmAction,

<button ... confirm-action="doIt()">Do It</button>

स्ट्रिंग है "doIt()", और आप एक स्ट्रिंग नहीं कह सकते हैं, जैसे "doIt()"()

आपका प्रश्न वास्तव में है:

जब मैं एक स्ट्रिंग के रूप में इसका नाम रखता हूं, तो मैं एक फ़ंक्शन को कैसे कॉल करूं?

जावास्क्रिप्ट में, आप ज्यादातर इस तरह डॉट नोटेशन का उपयोग करके कॉल करते हैं:

some_obj.greet()

लेकिन आप सरणी संकेतन का भी उपयोग कर सकते हैं:

some_obj['greet']

ध्यान दें कि इंडेक्स वैल्यू एक स्ट्रिंग कैसे है । तो, आपके निर्देश में आप बस यह कर सकते हैं:

  link: function (scope, element, attrs) {

    element.bind('click', function (e) {

      if (confirm(attrs.confirm)) {
        var func_str = attrs.confirmAction;
        var func_name = func_str.substring(0, func_str.indexOf('(')); // Or func_str.match(/[^(]+/)[0];
        func_name = func_name.trim();

        console.log(func_name); // => doIt
        scope[func_name]();
      }
    });
  }

+1 चूंकि फ़ंक्शन को पार्स करने का विचार मुश्किल था और मुझे इसी तरह की लेकिन एक और समस्या के साथ मदद की। धन्यवाद!
अनमोल सराफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.