2013-09-23 17 views
22

कार्य करने के लिए मैं AngularJS ढांचे के साथ बेहतर हो TodoMVC एप्लिकेशन का उपयोग कर रहा पारित करने के लिए।

<form id="todo-form" ng-submit="addTodo()"> 
    <input id="new-todo" placeholder="What needs to be done?" ng-model="newTodo" autofocus> 
</form> 

सूचना कैसे एनजी के लिये भेज निर्देश कॉल addTodo() newTodo मॉडल एक तर्क के रूप पारित किया जा रहा बिना समारोह: लाइनों 14-16 पर index.html में आप यह देख।

थोड़े समय बाद मैं निम्नलिखित कोड भर में बहुत ही फ़ाइल में लाइन 19 पर आया था:

<input id="toggle-all" type="checkbox" ng-model="allChecked" ng-click="markAll(allChecked)"> 

आप लेखक देख सकते हैं पारित करने के लिए markAll को मॉडल allChecked का फैसला किया() इस बार काम करो। अगर मैं सही ढंग से समझता हूं, तो वे $ scope.all संदर्भित कर सकते हैं इसे पास करने के बजाय नियंत्रक के अंदर चेक किया गया।

एक ही फ़ाइल में दो अलग-अलग दृष्टिकोणों का उपयोग क्यों करें? क्या कुछ परिस्थितियों में एक दृष्टिकोण बेहतर है? क्या यह असंगतता का मामला है या क्या इसका गहरा तर्क इस्तेमाल किया जा रहा है?

+1

यह आमतौर पर दायरे का मामला है। यदि आप एक एनजी-दोहराना का उपयोग करते हैं जो प्रत्येक पुनरावृत्ति के लिए बाल स्कॉप्स बनाता है, तो आप आवृत्ति चर को पैरामीटर के रूप में पास करना चाहते हैं। अन्यथा आप नहीं जानते कि यह क्या है। इसके अलावा, मैं कहूंगा कि यह सिर्फ वरीयता और लेखन की आसानी है। –

+0

मैंने [इस पोस्ट] पर स्कोप विरासत से संबंधित कुछ और शोध किए हैं (http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs/14049482 # 140,494,820)। मेरे विशिष्ट प्रश्न को स्पष्ट करने के लिए, मैं एक विधि या किसी अन्य का उपयोग करने के संबंध में कुछ सर्वोत्तम प्रथाओं की तलाश में हूं। यदि वे समान हैं, तो वही दायरा मानते हैं, तो मैं उस उत्तर को स्वीकार करूंगा। –

उत्तर

30

मैं हमेशा कार्य करने के लिए बहस में पारित करने के लिए पसंद करेंगे:

  • यह स्पष्ट क्या पैरामीटर समारोह की उम्मीद है।
  • यह क्योंकि सभी मापदंडों समारोह में इंजेक्ट किया जाता है इकाई परीक्षण करना आसान है (इकाई परीक्षण के लिए अच्छा)

निम्नलिखित स्थिति पर विचार करें:।

$scope.addToDo = function(){ 
    //This declaration is not clear what parameters the function expects. 
    if ($scope.parameter1){ 
     //do something with parameter2 
    }  
} 

और भी बदतर :

$scope.addToDo = function(){ 
    //This declaration is not clear what parameters the function expects. 
    if ($scope.someobject.parameter1){ //worse 

    }  
} 

गुंजाइश विरासतके कारणपैरेंट स्कोप से आ सकता है, parameter2 तक फ़ंक्शन के अंदर तंग युग्मन बनाता है, जब आप उस फ़ंक्शन को यूनिट-टेस्ट करने का प्रयास करते हैं तो परेशानी भी होती है।

अगर मैं इस तरह समारोह को परिभाषित:

//It's clearer that the function expects parameter1, parameter2 
$scope.addToDo = function(parameter1, parameter2){ 
    if (parameter1){ 
     //do something with parameter2 
    }  
} 

मामले अपने parameter2 माता पिता दायरे से प्राप्त होती है, आप अभी भी उस में देखने से गुजर सकता है। जब आप यूनिट-परीक्षण करते हैं, तो सभी पैरामीटर पास करना आसान होता है।

क्या तुमने कभी ASP.NET MVC के साथ काम किया है, तो आप कुछ इसी तरह नोटिस जाएगा: ढांचे के बजाय कार्रवाई समारोह में मानकों इंजेक्षन Request या HttpContext वस्तु से सीधे उस तक पहुंचने में करने की कोशिश करता

ऐसा भी दूसरों में अच्छा है ng-repeat

के साथ काम करने जैसा उल्लेख किया है मेरी राय में, कोणीय में नियंत्रक और मॉडल स्पष्ट रूप से अलग नहीं हैं। $ स्कोप ऑब्जेक्ट हमारे मॉडल की तरह गुणों और विधियों के साथ दिखता है (मॉडल में तर्क भी शामिल है)। ओओपी पृष्ठभूमि के लोग सोचेंगे कि: हम केवल उन पैरामीटर में गुजरते हैं जो ऑब्जेक्ट से संबंधित नहीं हैं। किसी वर्ग व्यक्ति की तरह पहले से ही hands है, हमें प्रत्येक ऑब्जेक्ट विधि के लिए hands में पास करने की आवश्यकता नहीं है। इस तरह एक उदाहरण कोड:

//assume that parameter1 belongs to $scope, parameter2 is inherited from parent scope. 
    $scope.addToDo = function(parameter2){ 
     if ($scope.parameter1){ //parameter1 could be accessed directly as it belongs to object, parameter2 should be passed in as parameter. 
      //do something with parameter2 
     } 
    } 
1

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

2

मुझे लगता है कि यह केवल कोड में विसंगति का एक मामला है। मैंने पहले इस प्रश्न पर विचार किया है और निम्नलिखित निष्कर्ष पर आया है ...

नियम: $ स्कोप फ़ंक्शंस में $ स्कोप चर को पास न करें।

नियंत्रक कोड पढ़ना प्रदर्शन करने के लिए क्या घटक के समारोह होगा पर्याप्त कोड होना चाहिए। दृश्य किसी भी व्यापार तर्क, बस बाइंडिंग (एनजी मॉडल, आदि एनजी क्लिक करें) शामिल नहीं होना चाहिए। यदि नियंत्रक में स्थानांतरित होने से दृश्य में कुछ स्पष्ट किया जा सकता है, तो हो।

अपवाद: सशर्त एनजी स्तरीय बयानों की अनुमति दें (जैसे ng-class='{active:$index==item.idx') - नियंत्रक में वर्ग सशर्त, डाल बहुत वर्बोज़ हो, और दृश्य से विचारों के साथ नियंत्रक के तर्क muddies कर सकते हैं। यदि यह एक दृश्य संपत्ति है, तो इसे ध्यान में रखें।

अपवाद: आप एक एनजी-दोहराने में किसी आइटम के साथ काम कर रहे हैं। उदाहरण के लिए:

<ul ng-repeat="item in items"> 
    <li><a ng-click="action(item)"><h1>{{item.heading}}</h1></a></li> 
</ul> 

मैं इन नियमों का पालन जब नियंत्रक लेखन & बार देखा गया है, और वे काम करने के लिए लग रहे हैं। उम्मीद है की यह मदद करेगा।

+2

मैं नियंत्रक में तर्क रखने और $ स्कोप फ़ंक्शंस में $ स्कोप चर को पारित करने के साथ सहमत नहीं हूं, लेकिन क्या यह कभी-कभी इकाई परीक्षण कोड की क्षमता को कम नहीं करता है, विशेष रूप से कार्य करता है? 'DisplayMessage (errMsg) 'की तुलना में एक फ़ंक्शन' displayMessage()' पर विचार करें। दूसरा संस्करण मेरी राय में परीक्षण करना बहुत आसान है। पहला संस्करण कार्यान्वयन विवरण और धारणाओं पर निर्भर करता है। आपका उत्तर अच्छी शुरूआत की तरह लगता है, लेकिन मुझे लगता है कि इन अन्य नियमों का पालन करते समय कोड को टेस्ट करने योग्य रखने पर चर्चा गायब है। –

+0

@ एडम थॉमस: हाँ, मैंने अधिक जानकारी के साथ अपना उत्तर अपडेट किया। 'यदि आपने कभी एएसपी.नेट एमवीसी के साथ काम किया है, तो आप कुछ इसी तरह देखेंगे: ढांचा सीधे अनुरोध या HttpContext ऑब्जेक्ट से इसे एक्सेस करने के बजाय पैरामीटर को क्रिया फ़ंक्शन में इंजेक्ट करने का प्रयास करता है। –

+0

@AdamThomas मुझे विश्वास नहीं है कि यह कोड को कम परीक्षण योग्य बनाता है। $ स्कोप की सामग्री नियंत्रक की स्थिति को परिभाषित करती है, और $ स्कोप विधियों का व्यवहार कैसे नियंत्रक की स्थिति पर निर्भर करेगा। दूसरी बात यह है कि मैं कुछ भी जटिल के लिए, आपके व्यवहार को निर्णय लेने के लिए कई तरीकों को ध्यान में रखना पड़ सकता है। आईएमओ फ़ंक्शंस जो बड़ी मात्रा में पैरामीटर लेते हैं, वे बहुत पठनीय नहीं होते हैं और इस मामले में फ़ंक्शन के लिए सीधे $ स्कोप से गुणों को पढ़ने के लिए बेहतर होगा। –

4

कस्टम व्यवहार विधियां, जैसे कि ng-click, ng-submit आदि हमें कॉल करने के तरीकों के पैरामीटर पास करने की अनुमति देती हैं। यह महत्वपूर्ण है क्योंकि हम ऐसा कुछ पारित करना चाहते हैं जो नियंत्रक में हैंडलर तक स्वतंत्र रूप से उपलब्ध न हो।उदाहरण के लिए,

angular.module('TestApp') 
.controller('TestAppController', ['$scope', function($scope) { 
    $scope.handler = function(idx) { 
     alert('clicked ' + idx.toString()); 
    }; 
}]); 

<ul> 
    <li ng-repeat="item in items"> 
     <button ng-click="handler($index)">{ item }</button> 
     <!-- $index is an iterator automatically available with ngRepeat --> 
    </li> 
</ul> 

अपने दूसरे उदाहरण के मामले में, allChecked के बाद से ही नियंत्रक जो markAll() को परिभाषित करता है के दायरे के भीतर है, तो आप बिल्कुल सही हैं, कुछ भी पारित करने के लिए कोई जरूरत नहीं है। हम केवल एक और प्रतिलिपि बना रहे हैं।

विधि को केवल दायरे में उपलब्ध चीज़ों का उपयोग करने के लिए पुन: उपयोग करना होगा।

$scope.markAll = function() { 
    todos.forEach(function (todo) { 
     todo.completed = $scope.allChecked; 
    }); 
}; 

इसलिए, हालांकि हमारे पास इन विधियों में पैरामीटर का उपयोग करने का विकल्प है, फिर भी उन्हें केवल कुछ समय की आवश्यकता होती है।

9

वहाँ, पहले भाग जो एक उत्तर दे रहा है इस उत्तर के दो हिस्से हैं बेहतर विकल्प है, दूसरे भाग के तथ्य यह है कि उनमें से कोई भी एक अच्छा विकल्प है!


कौन सा सही है?

यह एक है:

$scope.addToDo = function(params1, ...) { 
    alert(params1); 
} 

क्यों? क्योंकि ए - यह टेस्टेबल है। यह महत्वपूर्ण है भले ही आप परीक्षण नहीं लिख रहे हों, क्योंकि टेस्टेबल कोड जो लंबे समय तक हमेशा अधिक पठनीय और रखरखाव योग्य होता है।

यह बी के कारण भी बेहतर है - कॉलर की बात होने पर यह अज्ञेयवादी है। इस फ़ंक्शन को किसी भी प्रकार के विभिन्न नियंत्रकों/सेवाओं/आदि द्वारा पुन: उपयोग किया जा सकता है क्योंकि यह किसी दायरे के अस्तित्व या उस दायरे की संरचना पर निर्भर नहीं है।

आप के बजाय ऐसा करने जब:

$scope.addToDo = function() { 
    alert($scope.params1); 
} 

दोनों ए और बी असफल। यह आसानी से परीक्षण योग्य नहीं है, और इसे आसानी से पुन: उपयोग नहीं किया जा सकता है क्योंकि जिस क्षेत्र में आप इसका उपयोग करते हैं, उसे अलग-अलग स्वरूपित किया जा सकता है।

संपादित करें: आप कुछ बहुत बारीकी से अपने विशिष्ट दायरे से बंधा कर रहे हैं और टेम्पलेट से समारोह चला रहे हैं, तो आप में स्थितियों के लिए जहां यह पुन: प्रयोज्य सिर्फ मतलब नहीं है बनाने की कोशिश कर बनाये जा सकते हैं। समारोह बस सामान्य नहीं है। उस स्थिति में, इससे परेशान न हों, कुछ कार्यों का पुन: उपयोग नहीं किया जा सकता है। देखें कि मैंने आपके डिफ़ॉल्ट मोड के बारे में क्या लिखा है लेकिन याद रखें कि कुछ मामलों में यह फिट नहीं होगा।


क्यों दोनों गलत कर रहे हैं?

क्योंकि एक सामान्य नियम के रूप में आपको अपने नियंत्रकों में तर्क नहीं करना चाहिए, यह एक सेवा का काम है। नियंत्रक एक सेवा का उपयोग कर सकते हैं और फ़ंक्शन को कॉल कर सकते हैं या इसे मॉडल में बेनकाब कर सकते हैं, लेकिन इसे परिभाषित नहीं करना चाहिए।

यह महत्वपूर्ण क्यों है? क्योंकि फिर से यह फ़ंक्शन का पुन: उपयोग करना आसान बनाता है। नियंत्रक में परिभाषित एक फ़ंक्शन को किसी अन्य नियंत्रक में पुन: उपयोग नहीं किया जा सकता है, इस पर सीमा डालने के बिना कि HTML में नियंत्रकों को कैसे बुलाया जाता है। एक सेवा में परिभाषित एक समारोह इंजेक्शन और पुन: उपयोग किया जा सकता है जहां भी आपको ऐसा लगता है।

लेकिन मुझे फ़ंक्शन का पुन: उपयोग करने की आवश्यकता नहीं है! - हाँ आप करते हैं! शायद अभी नहीं और शायद इस विशिष्ट कार्य के लिए कभी नहीं, लेकिन जल्द या बाद में आप एक ऐसे फ़ंक्शन का पुन: उपयोग करना चाहते हैं जिसे आप आश्वस्त करते हैं कि आपको कभी भी पुन: उपयोग करने की आवश्यकता नहीं होगी। और फिर आपको कोड को फिर से काम करना होगा कि आप पहले से ही भुला चुके हैं, जो हमेशा अतिरिक्त समय लेते हैं।

शुरुआत से ही इसे ठीक से करना बेहतर है और सेवाओं में आपके द्वारा किए जा सकने वाले सभी तर्कों को स्थानांतरित करना बेहतर है। इस तरह, यदि आपको कभी उन्हें कहीं और चाहिए (यहां तक ​​कि किसी अन्य प्रोजेक्ट में) तो आप इसे पकड़ सकते हैं और इसे अपने वर्तमान स्कोप संरचना में फिट करने के लिए इसे फिर से लिखने के बिना इसका उपयोग कर सकते हैं।

बेशक, सेवाओं को आपके दायरे के बारे में पता नहीं है, इसलिए आपको पहले संस्करण का उपयोग करने के लिए मजबूर होना पड़ता है। बोनस!

app.service('ToDoService', [function(){ 
    this.addToDo = function(params1, ...){ 
     alert(params1); 
    } 
}]); 

और नियंत्रक के अंदर:: और एक सेवा के लिए पूरे दायरे गुजर का प्रलोभन, कि अंत कभी नहीं होगा अच्छी तरह से :-)

के लिए गिर नहीं है तो यह IMO सबसे अच्छा विकल्प है

$scope.addToDo = ToDoService.addToDo; 

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

लेकिन ऐसा लगता है कि यह मामला यहां नहीं है।

+0

बहुत अधिक सहमत हुए। आजकल लोग मॉडल में व्यापार तर्क डालते हैं जो एक मॉड्यूल है जो एक नियंत्रक के लिए विशिष्ट है। और मॉड्यूल के अंदर, यह अन्य तरीकों से प्रदान की जाने वाली सामान्य विधियों को कॉल कर सकता है। –

+1

मैं सहमत नहीं हूं। नियंत्रक के साथ कसकर तर्क को देखें नियंत्रक में होना चाहिए।कभी-कभी आपके पास कई निर्भरता के साथ बहुत जटिल इंटरफेस होता है जब क्या और क्या दिखाता/सक्षम/अक्षम होता है। सेवा का निर्माण करने का उपयोग क्यों करें इस नियंत्रक में केवल है? – Styx

+0

वैसे मैं आपके साथ सहमत हूं :) जैसा कि मैंने पिछले भाग में कहा था कि एक सेवा हमेशा सही जवाब नहीं होती है, न कि जब यह कुछ ऐसा होता है जो सीधे नियंत्रक से संबंधित होता है। उन मामलों में, जैसा कि आप कहते हैं, एक सेवा क्यों करें जब इसे शाब्दिक रूप से पुन: उपयोग नहीं किया जा सकता क्योंकि यह नियंत्रक और दृश्य पर निर्भर करता है। –

9

Zen of Angular पता चलता है:

 
Treat scope as read only in templates 
Treat scope as write only in controllers 

टेम्पलेट से मानकों के साथ इस सिद्धांत, आपको चाहिए हमेशा कॉल कार्यों स्पष्ट रूप से के बाद।

हालांकि, किसी भी शैली में आप अनुसरण करते हैं, तो आपको priorities और निर्देशों के निष्पादन के आदेश के बारे में सावधान रहना होगा। आपके उदाहरण में, using ng-model and ng-click leaves the order of execution of the two directives ambiguous। समाधान ng-change का उपयोग कर रहा है, जहां निष्पादन का आदेश स्पष्ट है: इसे पर मान परिवर्तनों के बाद निष्पादित किया जाएगा।

संबंधित मुद्दे