AngularJS: सेवा गुणों के लिए बाध्य करने का सही तरीका


162

मैं सबसे अच्छा अभ्यास के लिए देख रहा हूँ कि कैसे AngularJS में एक सेवा संपत्ति के लिए बाध्य किया जाए।

मैंने कई उदाहरणों के माध्यम से यह समझने के लिए काम किया है कि एंगुलरजेएस का उपयोग करके बनाई गई सेवा में गुणों को कैसे बांधें।

नीचे मेरे पास दो उदाहरण हैं कि मैं किसी सेवा में संपत्तियों को कैसे बांध सकता हूं; वे दोनों काम करते हैं। पहला उदाहरण बुनियादी बाइंडिंग का उपयोग करता है और दूसरा उदाहरण $ स्कोप का उपयोग किया जाता है। सेवा गुणों के साथ जुड़ने के लिए $ घड़ी

क्या किसी सेवा में संपत्तियों के लिए बाध्य करते समय या तो इन उदाहरणों को प्राथमिकता दी जाती है या क्या कोई अन्य विकल्प है जो मुझे नहीं पता है कि इसकी सिफारिश की जाएगी?

इन उदाहरणों का आधार यह है कि सेवा को प्रत्येक 5 सेकंड में अपने गुणों को "lastUpdated" और "कॉल" को अपडेट करना चाहिए। एक बार सेवा गुणों को अपडेट करने के बाद दृश्य को इन परिवर्तनों को प्रतिबिंबित करना चाहिए। ये दोनों उदाहरण सफलतापूर्वक काम करते हैं; मुझे आश्चर्य है कि अगर ऐसा करने का एक बेहतर तरीका है।

बुनियादी बंधन

निम्नलिखित कोड को यहाँ देखा और चलाया जा सकता है: http://plnkr.co/edit/d3c16z

<html>
<body ng-app="ServiceNotification" >

    <div ng-controller="TimerCtrl1" style="border-style:dotted"> 
        TimerCtrl1 <br/>
        Last Updated: {{timerData.lastUpdated}}<br/>
        Last Updated: {{timerData.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.timerData = Timer.data;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

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

$ गुंजाइश। $ घड़ी

निम्नलिखित कोड को यहाँ देखा और चलाया जा सकता है: http://plnkr.co/edit/dSBlC9

<html>
<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.$watch(function () { return Timer.data.lastUpdated; },
                function (value) {
                    console.log("In $watch - lastUpdated:" + value);
                    $scope.lastUpdated = value;
                }
            );

            $scope.$watch(function () { return Timer.data.calls; },
                function (value) {
                    console.log("In $watch - calls:" + value);
                    $scope.calls = value;
                }
            );
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

मुझे पता है कि मैं $ rootcope का उपयोग कर सकता हूं। सेवा में $ प्रसारण और $ root। नियंत्रक में $।, लेकिन अन्य उदाहरणों में मैंने बनाया है कि पहले प्रसारण पर $ प्रसारण / $ का उपयोग नहीं किया गया है। नियंत्रक, लेकिन अतिरिक्त कॉल जो प्रसारित होती हैं, उन्हें नियंत्रक में ट्रिगर किया जाता है। यदि आप $ rootcope को हल करने के तरीके से अवगत हैं। $ प्रसारण समस्या, कृपया एक उत्तर दें।

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


अपडेट करें

यह प्रश्न मूल रूप से अप्रैल 2013 में पूछा और उत्तर दिया गया था। मई 2014 में, गिल बिरमैन ने एक नया उत्तर प्रदान किया, जिसे मैंने सही उत्तर के रूप में बदल दिया। चूंकि गिल बिरमान के जवाब में बहुत कम वोट हैं, इसलिए मेरी चिंता यह है कि इस सवाल को पढ़ने वाले लोग कई अन्य वोटों के साथ अन्य उत्तरों के पक्ष में अपने जवाब की अवहेलना करेंगे। इससे पहले कि आप सबसे अच्छा उत्तर देने के बारे में निर्णय लें, मैं गिल बिरमैन के उत्तर की अत्यधिक अनुशंसा करता हूं।


मुझे लगता है कि जोश डेविड मिलर का जवाब बेहतर है कि गिल बर्मन का। और $ वॉच, $ वॉचग्रुप और $ वॉच कॉलेक्शन का उपयोग कर इसे और भी बेहतर बना सकते हैं। मध्यम से लेकर बड़े आकार के ऐप में चिंताओं का पृथक्करण बहुत महत्वपूर्ण है।
जोनाथन

@ बर्देव मुझे लगता है कि दोनों उत्तर उपयोगी नहीं थे, और नए डेवलपर्स उन्हें पूरी तरह से गलत समझेंगे।
ज़लाबोज़ा

जिस समस्या के बारे में आप पूछ रहे हैं वह संदर्भ वस्तुओं के देशी जावास्क्रिप्ट चर व्यवहार के बारे में है, मैंने नीचे थोड़ा स्पष्टीकरण दिया
ज़ालबोज़ा

जवाबों:


100

दूसरे दृष्टिकोण के कुछ पेशेवरों और विपक्षों पर विचार करें :

  • 0 के {{lastUpdated}} बजाय {{timerData.lastUpdated}}, जो आसानी से हो सकता है {{timer.lastUpdated}}, जो मैं बहस कर सकता हूं वह अधिक पठनीय है (लेकिन चलो बहस न करें ... मैं इस बिंदु को एक तटस्थ रेटिंग दे रहा हूं ताकि आप अपने लिए तय करें)

  • +1 यह सुविधाजनक हो सकता है कि कंट्रोलर मार्कअप के लिए एपीआई के एक प्रकार के रूप में कार्य करता है जैसे कि अगर किसी तरह डेटा मॉडल की संरचना आपको बदल सकती है (सिद्धांत रूप में) एचटीएमएल आंशिक को छूने के बिना नियंत्रक के एपीआई मैपिंग को अपडेट करें ।

  • -1 हालांकि, सिद्धांत हमेशा अभ्यास नहीं है और मैं आमतौर पर खुद को मार्कअप और नियंत्रक तर्क को संशोधित करने के लिए पाता हूं, जब भी परिवर्तन के लिए कहा जाता है । इसलिए एपीआई लिखने का अतिरिक्त प्रयास इसका फायदा उठाता है।

  • -1 इसके अलावा, यह दृष्टिकोण बहुत कम नहीं है।

  • -1 यदि आप डेटा को ng-modelअपने कोड से बाँधना चाहते हैं तो यह कम DRY हो जाता है क्योंकि आपको $scope.scalar_valuesएक नया REST कॉल करने के लिए कंट्रोलर में फिर से पैकेज करना होगा ।

  • -0.1 अतिरिक्त वॉचर (एस) बनाने वाला एक छोटा प्रदर्शन हिट है। इसके अलावा, यदि डेटा गुण मॉडल से जुड़े होते हैं, जिन्हें किसी विशेष नियंत्रक में देखने की आवश्यकता नहीं होती है, तो वे गहरी निगरानी करने वालों के लिए अतिरिक्त ओवरहेड बनाएंगे।

  • -1 क्या होगा यदि कई नियंत्रकों को समान डेटा मॉडल की आवश्यकता हो? इसका मतलब है कि आपके पास हर मॉडल में बदलाव के साथ कई एपीआई हैं।

$scope.timerData = Timer.data;के बारे में अभी प्रचलित आकर्षक लग रहा है ... चलो उस अंतिम बिंदु में थोड़ा गहरा गोता लगाएँ ... हम किस तरह के मॉडल परिवर्तन के बारे में बात कर रहे थे? बैक-एंड (सर्वर) पर एक मॉडल? या एक मॉडल जो बनाया गया है और केवल फ्रंट-एंड में रहता है? या तो मामले में, क्या अनिवार्य रूप से है डेटा मानचित्रण एपीआई में अंतर्गत आता है सामने के अंत सेवा परत , (एक कोणीय कारखाने या सेवा)। (ध्यान दें कि आपका पहला उदाहरण - मेरी प्राथमिकता-- सेवा की परत में ऐसा कोई एपीआई नहीं है , जो ठीक है क्योंकि यह काफी सरल है क्योंकि यह ऐसा नहीं करता है।)

अंत में , हर चीज को डीकोप नहीं करना पड़ता है। और जहाँ तक पूरी तरह से डेटा मॉडल से मार्कअप को डिकूप करने की बात है, कमियां फायदे को कम करती हैं।


नियंत्रकों, सामान्य रूप से नहीं होना चाहिए $scope = injectable.data.scalar। बल्कि, उन्हें $scope = injectable.data's promise.then(..)', और $scope.complexClickAction = function() {..}'s' के साथ छिड़का जाना चाहिए

एक वैकल्पिक दृष्टिकोण डेटा-decoupling और इस तरह दृश्य-कैप्सूलीकरण, केवल जगह है कि प्राप्त करने के लिए के रूप में यह वास्तव में समझ में आता है मॉडल से देखने दसगुणा है एक निर्देश के साथ । लेकिन वहां भी, $watchमान controllerया linkकार्यों में स्केलर नहीं है । इससे समय की बचत नहीं होगी और न ही कोड को अधिक रख-रखाव और न ही पठनीय बनाया जा सकेगा। यह परीक्षण को आसान भी नहीं बनाएगा क्योंकि कोणीय में मजबूत परीक्षण आमतौर पर परिणामस्वरूप DOM का परीक्षण करते हैं । बल्कि, एक निर्देश में आपके डेटा एपीआई को ऑब्जेक्ट रूप में मांगते हैं , और केवल $watchबनाए गए ers का उपयोग करके पक्ष लेते हैं ng-bind


उदाहरण http://plnkr.co/edit/MVeU1GKRTN4bqA3h9Yio

<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Bad:<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
        Good:<br/>
        Last Updated: {{data.lastUpdated}}<br/>
        Last Updated: {{data.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.data = Timer.data;
            $scope.lastUpdated = Timer.data.lastUpdated;
            $scope.calls = Timer.data.calls;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 500);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>

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

चिंताओं को अलग करना (लेकिन स्पर्श संबंधी रूप से), इसका एक और कारण है रक्षात्मक नकल जिसे मैं विचार करने में विफल रहा। यह सवाल ज्यादातर एक सेवा से सीधे डेटा पढ़ने से संबंधित है। लेकिन क्या होगा यदि आपकी टीम का कोई डेवलपर यह निर्णय लेता है कि दृश्य को प्रदर्शित करने से पहले नियंत्रक को कुछ तुच्छ तरीके से डेटा को बदलने की आवश्यकता है? (क्या नियंत्रकों को डेटा को सभी में बदलना चाहिए, यह एक और चर्चा है।) यदि वह पहले वस्तु की प्रतिलिपि नहीं बनाती है, तो वह अनजाने में किसी अन्य दृश्य घटक में प्रतिगमन का कारण बन सकती है जो समान डेटा का उपभोग करती है।

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

  1. चिंताओं का पृथक्करण : एक घटक प्रॉप्स के माध्यम से इसके सभी डेटा का उपभोग करता है और वैश्विक एकल (जैसे कोणीय सेवाओं) पर बहुत कम-से-कोई निर्भरता नहीं है, और दृश्य पदानुक्रम में इसके ऊपर क्या हुआ, इसके बारे में कुछ भी नहीं जानता है।

  2. म्यूटेबिलिटी : सभी प्रॉप्स अपरिवर्तनीय हैं, जो डेटा म्यूटेशन को अनजाने करने के जोखिम को समाप्त करता है।

ऊपर के दो बिंदुओं को प्राप्त करने के लिए एंगुलर 2.0 अब रिएक्ट से भारी उधार लेने की राह पर है।


1
अधिक मैं AngularJS के साथ काम कर रहा हूं जितना अधिक मैं समझता हूं। मेरा मानना ​​है कि AngularJS नियंत्रकों को यथासंभव सरल और पतला होना चाहिए। नियंत्रक में $ घड़ियाँ जोड़कर यह तर्क को जटिल करता है। सेवा में मूल्य को संदर्भित करने से यह बहुत सरल है और एंगुलरजेएस तरीके से अधिक प्रतीत होता है। -
माइक बार्लो - बर्डेव

3
AngularJS की "दस आज्ञाएँ"। यह एक कारण के लिए घोषणात्मक है।
पिलाउ ०

जोश डेविड मिलर का जवाब "INCORRECT" नहीं है। हर चीज के लिए एक समय और एक जगह होती है।
जोशुआ डेविड

मुझे लगता है कि आप सही हैं, @ फ़ायर कोडिंग। मैं उत्तर को अपडेट करने की योजना बना रहा हूं।
गिल बिरमन

@GilBirman उत्कृष्ट उत्तर। क्या आप निर्देशन के लिए लेखन और उदाहरण पर ध्यान देंगे? यह बताने के लिए कि आपने क्या कहा था "एकमात्र स्थान जो वास्तव में मॉडल से दृश्य को डिकूप करने के लिए समझ में आता है, एक निर्देश के साथ है। [...] एक निर्देश में, वस्तु रूप में आपके डेटा एपीआई की मांग करता है, और $ का उपयोग करके पक्ष लेता है। एनजी-बाइंड द्वारा बनाए गए दर्शक। "
klode

78

मेरे दृष्टिकोण से, $watchसबसे अच्छा अभ्यास तरीका होगा।

आप वास्तव में अपने उदाहरण को थोड़ा सरल कर सकते हैं:

function TimerCtrl1($scope, Timer) {
  $scope.$watch( function () { return Timer.data; }, function (data) {
    $scope.lastUpdated = data.lastUpdated;
    $scope.calls = data.calls;
  }, true);
}

बस इतना ही चाहिए।

चूंकि गुण एक साथ अपडेट किए गए हैं, इसलिए आपको केवल एक घड़ी की आवश्यकता है। इसके अलावा, चूंकि वे एकल, बल्कि छोटी वस्तु से आते हैं, इसलिए मैंने इसे केवल Timer.dataसंपत्ति देखने के लिए बदल दिया । अंतिम पैरामीटर $watchयह बताने के लिए कि यह समान है, यह सुनिश्चित करने के बजाय गहरी समानता के लिए जाँच करने के लिए पारित किया गया है।


थोड़ा संदर्भ प्रदान करने के लिए, मैं इस पद्धति को सीधे सेवा मूल्य को दायरे में रखने के लिए पसंद करूंगा ताकि चिंताओं का उचित पृथक्करण सुनिश्चित किया जा सके। आपके दृश्य को संचालित करने के लिए आपकी सेवाओं के बारे में कुछ भी जानने की आवश्यकता नहीं होनी चाहिए। नियंत्रक का काम सब कुछ एक साथ गोंद करना है; इसका काम आपकी सेवाओं से डेटा प्राप्त करना और उन्हें आवश्यक तरीके से संसाधित करना और फिर जो भी विशिष्टताओं की आवश्यकता होती है, उसके साथ अपना दृष्टिकोण प्रदान करना है। लेकिन मुझे नहीं लगता कि इसका काम सिर्फ सर्विस को सही तरीके से देखना है। अन्यथा, नियंत्रक भी वहाँ क्या कर रहा है? AngularJS डेवलपर्स ने उसी तर्क का पालन किया जब उन्होंने टेम्प्लेट (उदाहरण ifकथन) में किसी भी "तर्क" को शामिल नहीं करने का विकल्प चुना ।

निष्पक्ष होने के लिए, संभवतः यहां कई दृष्टिकोण हैं और मैं अन्य उत्तरों की प्रतीक्षा कर रहा हूं।


3
क्या आप थोड़ा विस्तार कर सकते हैं? क्या आप $ घड़ियों को पसंद करते हैं क्योंकि दृश्य सेवा के लिए कम है? Ie, {{lastUpdated}}बनाम{{timerData.lastUpdated}}
मार्क राजकोक

2
Timer.data$ वॉच में उपयोग करने के लिए @ बर्डेव Timerको $ स्कोप पर परिभाषित किया जाना है, क्योंकि स्ट्रींग एक्सप्रेशन जो आप $ वॉच से गुजरते हैं, का स्कोप के विरुद्ध मूल्यांकन किया जाता है। यहां एक प्लंकर है जो दिखाता है कि उस काम को कैसे करना है। ऑब्जेक्टक्वाइटी पैरामीटर को यहां दर्ज किया गया है - तीसरा पैरामीटर - लेकिन वास्तव में बहुत अच्छी तरह से समझाया नहीं गया है।
मार्क राजकॉक

2
प्रदर्शन बुद्धिमान, $watchकाफी अक्षम है। Stackoverflow.com/a/17558885/932632 और stackoverflow.com/questions/12576798/…
Krym

11
@ किरम शायद कुछ परिस्थितियों में सच है, लेकिन जब प्रदर्शन से निपटने के लिए हमें सांख्यिकीय रूप से महत्वपूर्ण, सामान्यीकृत लोगों के बजाय "चिकित्सकीय रूप से महत्वपूर्ण" प्रदर्शन बढ़ाने की आवश्यकता होती है। यदि किसी मौजूदा एप्लिकेशन में कोई प्रदर्शन समस्या है, तो उसे संबोधित किया जाना चाहिए। अन्यथा, यह सिर्फ समय से पहले अनुकूलन का मामला है, जो कठिन-से-पढ़ने, बग-प्रवण कोड की ओर जाता है जो सर्वोत्तम प्रथाओं का पालन नहीं करता है और जिसका कोई लाभ नहीं है।
जोश डेविड मिलर

1
देखने वाले की मानें तो एक कॉल करने के लिए एक फ़ंक्शन का उपयोग करता है, तो हाँ। यह अच्छा काम करता है। मैं भी एक संग्रह में उदाहरणों को वापस करने वाली सेवाओं का प्रस्तावक हूं, जहां गेट 5 की ester और सेटर सुविधाएँ काफी अच्छी तरह से हैं।
जोश डेविड मिलर

19

पार्टी के लिए देर से, लेकिन भविष्य के Googlers के लिए - दिए गए उत्तर का उपयोग न करें।

जावास्क्रिप्ट में संदर्भ द्वारा वस्तुओं को पास करने का एक तंत्र है, जबकि यह केवल "संख्याओं, तारों आदि" के मूल्यों के लिए एक उथली प्रतिलिपि से गुजरता है।

उपरोक्त उदाहरण में, किसी सेवा के बाध्यकारी गुणों के बजाय, हम सेवा को दायरे में क्यों नहीं लाते हैं?

$scope.hello = HelloService;

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

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

अंतिम टिप: यदि आप अपना समय अपनी सेवाओं से अधिक अपने नियंत्रक पर काम करने में बिताते हैं तो आप इसे गलत कर रहे हैं :(

आपके द्वारा प्रदत्त उस विशेष डेमो कोड में मैं आपको करने की सलाह दूंगा:

 function TimerCtrl1($scope, Timer) {
   $scope.timer = Timer;
 }
///Inside view
{{ timer.time_updated }}
{{ timer.other_property }}
etc...

संपादित करें:

जैसा कि मैंने ऊपर उल्लेख किया है, आप अपनी सेवा विशेषताओं के उपयोग को नियंत्रित कर सकते हैं defineProperty

उदाहरण:

// Lets expose a property named "propertyWithSetter" on our service
// and hook a setter function that automatically saves new value to db !
Object.defineProperty(self, 'propertyWithSetter', {
  get: function() { return self.data.variable; },
  set: function(newValue) { 
         self.data.variable = newValue; 
         // let's update the database too to reflect changes in data-model !
         self.updateDatabaseWithNewData(data);
       },
  enumerable: true,
  configurable: true
});

अब हमारे कंट्रोलर में अगर हम

$scope.hello = HelloService;
$scope.hello.propertyWithSetter = 'NEW VALUE';

हमारी सेवा का मान बदल जाएगा propertyWithSetterऔर नए मूल्य को किसी भी तरह डेटाबेस में पोस्ट कर देगा!

या हम कोई भी तरीका अपना सकते हैं।

का संदर्भ लें MDN दस्तावेजीकरण के लिए defineProperty


बहुत यकीन है कि जो मैं ऊपर वर्णन कर रहा था $scope.model = {timerData: Timer.data};, सीधे स्कोप पर सीधे मॉडल के बजाय इसे संलग्न करना।
स्कॉट सिल्वी

1
AFAIK, js ऑब्जेक्ट संदर्भ सेवा में सब कुछ के लिए काम करता है। इस तरह से कोडिंग करना: $ गुंजाइश। कॉन्ट्रोवर्लर = सर्विस विवर, आप जो कुछ भी करते हैं वह $ स्कोप में होता है। कॉन्ट्रोवर्लर भी सर्विसविअर में किया जाता है।
काई वांग

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

12

मुझे लगता है कि इस प्रश्न का संदर्भ घटक है।

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

इसके अलावा, कोणीय में प्रदर्शन दो चीजों पर आधारित है। पहला यह है कि एक पृष्ठ पर कितने बाइंडिंग हैं। दूसरा यह है कि कैसे महंगा पाने वाले कार्य हैं। मिस्को यहां इस बारे में बात करता है

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

एक चेतावनी के रूप में, आपको सीधे अपने $ स्कोप से किसी भी गुण को नहीं लटकाया जाना चाहिए । $scopeचर अपने मॉडल नहीं है। इसमें आपके मॉडल के संदर्भ हैं।

मेरे दिमाग में, सेवा को नीचे से देखने की जानकारी प्राप्त करने के लिए "सर्वोत्तम अभ्यास":

function TimerCtrl1($scope, Timer) {
  $scope.model = {timerData: Timer.data};
};

और फिर आपके विचार में शामिल होगा {{model.timerData.lastupdated}}


उस सुझाव के साथ सावधान, कोई व्यक्ति जो जावास्क्रिप्ट में विशेषज्ञ नहीं है, वह एक संपत्ति के साथ ऐसा करने की कोशिश कर सकता है जो एक स्ट्रिंग है। उस स्थिति में जावास्क्रिप्ट ऑब्जेक्ट के लिए संदर्भ नहीं बनाता है, लेकिन स्ट्रिंग स्ट्रिंग को कॉपी करता है। (और यह बुरा कारण है कि यह अद्यतन नहीं होता है, अगर यह बदल जाता है)
Valerio

7
क्या मैंने अपने 'कैविएट' को कवर नहीं किया था कि आपको हमेशा डॉट का उपयोग करना चाहिए (मतलब इसे $ स्कोप से नहीं लटकाना चाहिए, लेकिन $ स्कोप.मॉडल से)। यदि आपके पास $ गुंजाइश.model.someStringProperty है, और आप अपने दृष्टिकोण में model.someStringProperty का संदर्भ देते हैं, तो यह अपडेट हो जाएगा, क्योंकि आंतरिक वॉचर्स ऑब्जेक्ट पर होंगे, न कि प्रोप।
स्कॉट सिल्वी

6

ऊपर दिए गए उदाहरणों के आधार पर मैंने सोचा कि मैं एक नियंत्रक चर को सेवा चर में पारदर्शी रूप से बांधने के तरीके से फेंक दूंगा।

नीचे दिए गए उदाहरण में नियंत्रक $scope.countचर में परिवर्तन स्वचालित रूप से सेवा countचर में परिलक्षित होगा ।

उत्पादन में हम वास्तव में एक सेवा पर एक आईडी को अपडेट करने के लिए इस बाध्यकारी का उपयोग कर रहे हैं जो तब एसिंक्रोनस रूप से डेटा प्राप्त करता है और इसकी सेवा var को अपडेट करता है। इसके अलावा बाइंडिंग का मतलब है कि कंट्रोलर ऑटोमैटिकली अपडेट हो जाते हैं जब सर्विस अपडेट हो जाती है।

नीचे दिए गए कोड को http://jsfiddle.net/xuUHS/163/ पर काम करते देखा जा सकता है

राय:

<div ng-controller="ServiceCtrl">
    <p> This is my countService variable : {{count}}</p>
    <input type="number" ng-model="count">
    <p> This is my updated after click variable : {{countS}}</p>

    <button ng-click="clickC()" >Controller ++ </button>
    <button ng-click="chkC()" >Check Controller Count</button>
    </br>

    <button ng-click="clickS()" >Service ++ </button>
    <button ng-click="chkS()" >Check Service Count</button>
</div>

सेवा / नियंत्रक:

var app = angular.module('myApp', []);

app.service('testService', function(){
    var count = 10;

    function incrementCount() {
      count++;
      return count;
    };

    function getCount() { return count; }

    return {
        get count() { return count },
        set count(val) {
            count = val;
        },
        getCount: getCount,
        incrementCount: incrementCount
    }

});

function ServiceCtrl($scope, testService)
{

    Object.defineProperty($scope, 'count', {
        get: function() { return testService.count; },
        set: function(val) { testService.count = val; },
    });

    $scope.clickC = function () {
       $scope.count++;
    };
    $scope.chkC = function () {
        alert($scope.count);
    };

    $scope.clickS = function () {
       ++testService.count;
    };
    $scope.chkS = function () {
        alert(testService.count);
    };

}

यह एक भयानक समाधान है, धन्यवाद, इसने मुझे करने में बहुत मदद की, बहुत ही स्मार्ट तरीके से :)
जेविस पेरेज़

2

मुझे लगता है कि यह उस पर मौजूद विशेषताओं के बजाय सेवा पर खुद को बांधने का एक बेहतर तरीका है।

यहाँ पर क्यों:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular.min.js"></script>
<body ng-app="BindToService">

  <div ng-controller="BindToServiceCtrl as ctrl">
    ArrService.arrOne: <span ng-repeat="v in ArrService.arrOne">{{v}}</span>
    <br />
    ArrService.arrTwo: <span ng-repeat="v in ArrService.arrTwo">{{v}}</span>
    <br />
    <br />
    <!-- This is empty since $scope.arrOne never changes -->
    arrOne: <span ng-repeat="v in arrOne">{{v}}</span>
    <br />
    <!-- This is not empty since $scope.arrTwo === ArrService.arrTwo -->
    <!-- Both of them point the memory space modified by the `push` function below -->
    arrTwo: <span ng-repeat="v in arrTwo">{{v}}</span>
  </div>

  <script type="text/javascript">
    var app = angular.module("BindToService", []);

    app.controller("BindToServiceCtrl", function ($scope, ArrService) {
      $scope.ArrService = ArrService;
      $scope.arrOne = ArrService.arrOne;
      $scope.arrTwo = ArrService.arrTwo;
    });

    app.service("ArrService", function ($interval) {
      var that = this,
          i = 0;
      this.arrOne = [];
      that.arrTwo = [];

      $interval(function () {
        // This will change arrOne (the pointer).
        // However, $scope.arrOne is still same as the original arrOne.
        that.arrOne = that.arrOne.concat([i]);

        // This line changes the memory block pointed by arrTwo.
        // And arrTwo (the pointer) itself never changes.
        that.arrTwo.push(i);
        i += 1;
      }, 1000);

    });
  </script>
</body> 

आप इसे इस प्लंकर पर खेल सकते हैं ।


1

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


0

किसी भी डेटा को बांधने के लिए, जो सेवा भेजता है एक अच्छा विचार (वास्तुकला) नहीं है, लेकिन अगर आपको इसकी आवश्यकता है, तो मैं आपको यह करने के लिए 2 तरीके सुझाता हूं

1) आप डेटा को आपके सेवा के अंदर नहीं प्राप्त कर सकते हैं। आप अपने नियंत्रक / निर्देश के अंदर डेटा प्राप्त कर सकते हैं और आपको इसे कहीं भी बांधने की समस्या नहीं होगी

2) आप कोणीय घटनाओं का उपयोग कर सकते हैं। जब भी आप चाहें, आप एक संकेत भेज सकते हैं ($ rootScope से) और जहाँ भी आप चाहें इसे पकड़ सकते हैं। आप उस ईवेंट पर एक डेटा भी भेज सकते हैं।

शायद यह आपकी मदद कर सकता है। यदि आपको उदाहरणों के साथ अधिक की आवश्यकता है, तो यहां लिंक है

http://www.w3docs.com/snippets/angularjs/bind-value-between-service-and-controller-directive.html


-1

व्हाट अबाउट

scope = _.extend(scope, ParentScope);

पेरेंटस्कोप एक इंजेक्शन सेवा कहां है?


-2

सबसे सुरुचिपूर्ण समाधान ...

app.service('svc', function(){ this.attr = []; return this; });
app.controller('ctrl', function($scope, svc){
    $scope.attr = svc.attr || [];
    $scope.$watch('attr', function(neo, old){ /* if necessary */ });
});
app.run(function($rootScope, svc){
    $rootScope.svc = svc;
    $rootScope.$watch('svc', function(neo, old){ /* change the world */ });
});

इसके अलावा, मैं EDA (ईवेंट-चालित आर्किटेक्चर) लिखता हूं, इसलिए मैं निम्नलिखित [oversimplified संस्करण] जैसा कुछ करना चाहता हूं:

var Service = function Service($rootScope) {
    var $scope = $rootScope.$new(this);
    $scope.that = [];
    $scope.$watch('that', thatObserver, true);
    function thatObserver(what) {
        $scope.$broadcast('that:changed', what);
    }
};

फिर, मैंने वांछित चैनल पर अपने नियंत्रक में एक श्रोता को रखा और बस इस तरह से अपने स्थानीय दायरे को बनाए रखा।

अंत में, "बेस्ट प्रैक्टिस" का बहुत कुछ नहीं है - बल्कि, इसकी ज्यादातर वरीयता - जब तक आप चीजों को सॉलिड रख रहे हैं और कमजोर रोपाई को नियोजित कर रहे हैं। कारण मैं बाद के कोड की वकालत करूंगा क्योंकि EDA के पास प्रकृति द्वारा संभव सबसे कम युग्मन है। और अगर आप इस तथ्य से बहुत चिंतित नहीं हैं, तो आइए हम एक साथ एक ही प्रोजेक्ट पर काम करने से बचें।

उम्मीद है की यह मदद करेगा...

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