App.config में इंजेक्शन सेवा


168

मैं एक सेवा को app.config में इंजेक्ट करना चाहता हूं, ताकि नियंत्रक को कॉल करने से पहले डेटा को पुनर्प्राप्त किया जा सके। मैंने इसे इस तरह आज़माया:

सर्विस:

app.service('dbService', function() {
    return {
        getData: function($q, $http) {
            var defer = $q.defer();
            $http.get('db.php/score/getData').success(function(data) {
                defer.resolve(data);            
            });
            return defer.promise;
        }
    };
});

कॉन्फ़िग:

app.config(function ($routeProvider, dbService) {
    $routeProvider
        .when('/',
        {
            templateUrl: "partials/editor.html",
            controller: "AppCtrl",
            resolve: {
                data: dbService.getData(),
            }
        })
});

लेकिन मुझे यह त्रुटि मिली:

त्रुटि: अज्ञात प्रदाता: EditorApp से dbService

सेटअप को सही कैसे करें और इस सेवा को कैसे इंजेक्ट करें?


3
पहले से ही आपने जो कुछ भी देखा है, उसके बावजूद आप जो चाहते हैं उसे हासिल करने का एक तरीका है, और AngularJS ने इस प्रकार की कार्यक्षमता को सक्षम करने में बहुत समय बिताया है। इसे प्राप्त करने के बारे में मेरे उत्तर की समीक्षा करें।
ब्रायन वेंडरबस

जवाबों:


131

एलेक्स ऐसा करने में सक्षम नहीं होने का सही कारण प्रदान करता है जो आप करने की कोशिश कर रहे हैं, इसलिए +1। लेकिन आप इस मुद्दे का सामना कर रहे हैं क्योंकि आप काफी हल नहीं कर रहे हैं कि वे कैसे डिज़ाइन किए गए हैं।

resolveया तो एक सेवा की स्ट्रिंग या एक मान इंजेक्ट होने के लिए एक मान लौटाता है। चूंकि आप उत्तरार्द्ध कर रहे हैं, आपको वास्तविक कार्य में पास होना चाहिए:

resolve: {
  data: function (dbService) {
    return dbService.getData();
  }
}

जब फ्रेमवर्क हल हो जाता है data, तो यह dbServiceफंक्शन में इंजेक्ट हो जाता है ताकि आप स्वतंत्र रूप से इसका इस्तेमाल कर सकें। आपको इसमें इंजेक्ट करने की आवश्यकता नहीं हैconfigइसे पूरा करने के ब्लॉक में ।

बॉन एपेतीत!


2
धन्यवाद! हालाँकि, अगर मैं ऐसा करता हूं तो मुझे यह मिलता है: त्रुटि: सेवा में 'अपरिभाषित' कोई वस्तु नहीं है ('$ q.defer' का मूल्यांकन)।
dndr

1
इंजेक्शन उच्च-स्तरीय समारोह के लिए पारित में होता है .service, तो ले जाने $qऔर $httpवहाँ।
जोश डेविड मिलर

1
@ XMLilley एक संकल्प में स्ट्रिंग वास्तव में एक सेवा का नाम है और सेवा पर कोई विशेष कार्य नहीं है। अपने उदाहरण का उपयोग करते हुए, आप कर सकते थे pageData: 'myData', लेकिन आपको pageData.overviewअपने नियंत्रक से कॉल करना होगा । स्ट्रिंग विधि शायद केवल उपयोगी है अगर सेवा कारखाने ने एक एपीआई के बजाय एक वादा वापस किया। तो जिस तरह से आप वर्तमान में कर रहे हैं वह शायद सबसे अच्छा तरीका है।
जोश डेविड मिलर

2
@BrianVanderbusch मुझे कुछ भ्रम की स्थिति को स्वीकार करना चाहिए जहाँ आपको लगता है कि हम असहमत हैं। ओपी को हुई वास्तविक समस्या यह थी कि उसने एक सेवा को एक कॉन्फ़िगर ब्लॉक में इंजेक्ट किया था, जो नहीं किया जा सकता है । समाधान सेवा को संकल्प में इंजेक्ट करना है । हालांकि आपके उत्तर ने सेवा कॉन्फ़िगरेशन के बारे में बहुत सारे विवरण प्रदान किए हैं, मैं यह नहीं देखता कि यह ओपी के सामने आई त्रुटि से किसी भी तरह से संबंधित है, और ओपी की समस्या का आपका समाधान बिल्कुल वैसा ही था : आपने समाधान फ़ंक्शन में सेवा को इंजेक्ट किया और नहीं config कार्य करते हैं। क्या आप विस्तार से बता सकते हैं कि हम यहाँ कहाँ असहमत हैं?
जोश डेविड मिलर

1
@JoshDavidMiller मैंने जिस विधि का प्रदर्शन किया, उसका उपयोग राज्य सक्रियण से पहले एक सेवा को कॉन्फ़िगर करने के लिए संभव है, जैसे कि कॉन्फ़िगरेशन चरण के दौरान त्रुटियों को फेंका / संभाला जा सकता है, संभावित रूप से यह बदलते हुए कि आप एप्लिकेशन बूटस्ट्रैपिंग से पहले अन्य कॉन्फ़िगरेशन मानों को तुरंत कैसे बदल देंगे। उदाहरण के लिए, एप्लिकेशन की सही विशेषताओं को संकलित करने के लिए उपयोगकर्ता की भूमिका का निर्धारण करना।
ब्रायन वेंडरबस

140

एक कस्टम AngularJS प्रदाता के रूप में अपनी सेवा सेट करें

स्वीकृत जवाब के बावजूद, आप वास्तव में वही कर सकते हैं जो आप करने का इरादा कर रहे थे, लेकिन आपको इसे एक कॉन्फ़िगर करने योग्य प्रदाता के रूप में स्थापित करने की आवश्यकता है, ताकि यह कॉन्फ़िगरेशन चरण के दौरान एक सेवा के रूप में उपलब्ध हो .. सबसे पहले, Serviceएक प्रदाता को बदलें जैसा की नीचे दिखाया गया। यहां मुख्य अंतर यह है कि मूल्य निर्धारित करने के बाद defer, आपने defer.promiseसंपत्ति को वादे के आधार पर वापस कर दिया$http.get :

प्रदाता सेवा: (प्रदाता: सेवा नुस्खा)

app.provider('dbService', function dbServiceProvider() {

  //the provider recipe for services require you specify a $get function
  this.$get= ['dbhost',function dbServiceFactory(dbhost){
     // return the factory as a provider
     // that is available during the configuration phase
     return new DbService(dbhost);  
  }]

});

function DbService(dbhost){
    var status;

    this.setUrl = function(url){
        dbhost = url;
    }

    this.getData = function($http) {
        return $http.get(dbhost+'db.php/score/getData')
            .success(function(data){
                 // handle any special stuff here, I would suggest the following:
                 status = 'ok';
                 status.data = data;
             })
             .error(function(message){
                 status = 'error';
                 status.message = message;
             })
             .then(function(){
                 // now we return an object with data or information about error 
                 // for special handling inside your application configuration
                 return status;
             })
    }    
}

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

config:

app.config(function ($routeProvider) { 
    $routeProvider
        .when('/', {
            templateUrl: "partials/editor.html",
            controller: "AppCtrl",
            resolve: {
                dbData: function(DbService, $http) {
                     /*
                     *dbServiceProvider returns a dbService instance to your app whenever
                     * needed, and this instance is setup internally with a promise, 
                     * so you don't need to worry about $q and all that
                     */
                    return DbService('http://dbhost.com').getData();
                }
            }
        })
});

अपने में हल किए गए डेटा का उपयोग करें appCtrl

app.controller('appCtrl',function(dbData, DbService){
     $scope.dbData = dbData;

     // You can also create and use another instance of the dbService here...
     // to do whatever you programmed it to do, by adding functions inside the 
     // constructor DbService(), the following assumes you added 
     // a rmUser(userObj) function in the factory
     $scope.removeDbUser = function(user){
         DbService.rmUser(user);
     }

})

संभव विकल्प

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

app.config(function($routeProvider, $provide) {
    $provide.service('dbService',function(){})
    //set up your service inside the module's config.

    $routeProvider
        .when('/', {
            templateUrl: "partials/editor.html",
            controller: "AppCtrl",
            resolve: {
                data: 
            }
        })
});

कुछ सहायक संसाधन

  • जॉन लिंडक्विस्ट का एक उत्कृष्ट 5 मिनट का स्पष्टीकरण और एग्जहेड.आईओ पर इसका प्रदर्शन है , और यह मुफ्त पाठों में से एक है! मैंने मूल रूप से उसके प्रदर्शन को संशोधित करके बनाया है$http अनुरोध को इस अनुरोध के संदर्भ में विशिष्ट
  • पर AngularJS डेवलपर गाइड देखें प्रदाता
  • चालाक / के बारे में factory/ service/ provider पर एक उत्कृष्ट व्याख्या भी है ।

प्रदाता आपको .serviceविधि के बारे में थोड़ा और विन्यास देता है , जो इसे एक एप्लिकेशन स्तर प्रदाता के रूप में बेहतर बनाता है, लेकिन आप इसे कॉन्फ़िगर करने के लिए कॉन्फ़िगर ऑब्जेक्ट के भीतर इसे भी एन्क्रिप्ट कर सकते हैं $provideजैसे:


2
धन्यवाद, मैं इस तरह के एक उदाहरण के लिए देख रहा था; विस्तृत जवाब और महान लिंक!
cnlevy

1
कोई दिक्कत नहीं है! यह SO पर मेरा पसंदीदा उत्तर है। मैंने इसका उत्तर तब दिया जब वर्तमान में स्वीकृत उत्तर पहले से ही उत्तर दिया गया था, और 18 वोट थे। कुछ बैज के लिए अच्छा है!
ब्रायन वेंडरबस

यह वास्तव में उपयोगी होगा यदि आपके कोडपेन नमूने काम करते हैं। उदाहरण के लिए, $ प्रदान। सेवा ('dbService', फ़ंक्शन) () {के पास $ http इंजेक्ट नहीं है, लेकिन इसके शरीर में उपयोग होता है। जैसा कि यह खड़ा है, मुझे आपकी तकनीक 2 काम करने के लिए नहीं मिल सकती है। यह बहुत निराशाजनक है कि यह स्टार्टअप में एक कोणीय कार्यक्रम में एक हटाए गए फ़ाइल से कॉन्फ़िगर डेटा लोड करने के लिए बहुत मुश्किल है।
बर्नार्ड

@Alkaline मैंने इस पोस्ट के बाद से एक या दो चीजें सीखी हैं। उत्तर सिद्धांत में सही है लेकिन इसमें 1 या 2 चीजें हैं (1 जो आपने इंगित की है) जो तय की जानी चाहिए। टिप्पणी के लिए धन्यवाद। मैं उत्तर की समीक्षा करूंगा और अपडेट करूंगा। इस समय के लिए कोडपे को हटा दिया गया ... इसे पूरा करने का कभी मौका नहीं मिला।
ब्रायन वेंडरबसच

5
मुझे लगता है कि आपके द्वारा दी गई जानकारी गलत है। आप एक प्रदाता का उपयोग कर सकते हैं लेकिन कॉन्फ़िगरेशन चरण के दौरान आप $getकॉल के परिणाम के साथ काम नहीं कर रहे हैं । इसके बजाय आप प्रदाता उदाहरण पर तरीके जोड़ना चाहते हैं और thisजब आप कॉल करते हैं तो बस वापस आ जाते हैं $get। वास्तव में आपके उदाहरण में आप बस एक सेवा का उपयोग कर सकते हैं ... एक प्रदाता में आप सेवाओं को भी इंजेक्ट नहीं कर सकते हैं $http। और btw यह //return the factory as a provider, that is available during the configuration phaseभ्रामक / गलत जानकारी है
डिटर्जेंट

21

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

इस प्रश्न और उत्तर को देखें: मॉड्यूल.कॉन्फिग के अंदर मूल्य का एंगुलरजेएस निर्भरता इंजेक्शन

एक मॉड्यूल कॉन्फ़िगरेशन और रन ब्लॉक का एक संग्रह है जो बूटस्ट्रैप प्रक्रिया के दौरान आवेदन पर लागू होता है। इसके सरलतम रूप में मॉड्यूल में दो प्रकार के ब्लॉकों का संग्रह होता है:

कॉन्फ़िगरेशन ब्लॉक - प्रदाता पंजीकरण और कॉन्फ़िगरेशन चरण के दौरान निष्पादित हो जाते हैं। केवल प्रदाताओं और स्थिरांक को कॉन्फ़िगरेशन ब्लॉक में इंजेक्ट किया जा सकता है। यह पूरी तरह से कॉन्फ़िगर किए जाने से पहले सेवाओं की आकस्मिक तात्कालिकता को रोकने के लिए है।


2
वास्तव में, यह किया जा सकता है। समझाने पर शीघ्र ही जवाब देना।
ब्रायन वैंडरबुश

5

मुझे नहीं लगता कि आप ऐसा करने में सक्षम हो सकते हैं, लेकिन मैंने एक सेवा को सफलतापूर्वक configब्लॉक में इंजेक्ट किया है । (AngularJS v1.0.7)

angular.module('dogmaService', [])
    .factory('dogmaCacheBuster', [
        function() {
            return function(path) {
                return path + '?_=' + Date.now();
            };
        }
    ]);

angular.module('touch', [
        'dogmaForm',
        'dogmaValidate',
        'dogmaPresentation',
        'dogmaController',
        'dogmaService',
    ])
    .config([
        '$routeProvider',
        'dogmaCacheBusterProvider',
        function($routeProvider, cacheBuster) {
            var bust = cacheBuster.$get[0]();

            $routeProvider
                .when('/', {
                    templateUrl: bust('touch/customer'),
                    controller: 'CustomerCtrl'
                })
                .when('/screen2', {
                    templateUrl: bust('touch/screen2'),
                    controller: 'Screen2Ctrl'
                })
                .otherwise({
                    redirectTo: bust('/')
                });
        }
    ]);

angular.module('dogmaController', [])
    .controller('CustomerCtrl', [
        '$scope',
        '$http',
        '$location',
        'dogmaCacheBuster',
        function($scope, $http, $location, cacheBuster) {

            $scope.submit = function() {
                $.ajax({
                    url: cacheBuster('/customers'),  //server script to process data
                    type: 'POST',
                    //Ajax events
                    // Form data
                    data: formData,
                    //Options to tell JQuery not to process data or worry about content-type
                    cache: false,
                    contentType: false,
                    processData: false,
                    success: function() {
                        $location
                            .path('/screen2');

                        $scope.$$phase || $scope.$apply();
                    }
                });
            };
        }
    ]);

सेवा विधि का नाम dogmaCacheBuster है लेकिन .configआपने cacheBuster (जो उत्तर में कहीं भी परिभाषित नहीं है) और dogmaCacheBusterProvider (जिसका आगे उपयोग नहीं किया गया है) लिखा है । क्या आप इस पर स्पष्टीकरण देंगे?
diEcho

@ pro.mean मुझे लगता है कि मैं उस तकनीक का प्रदर्शन कर रहा था, जिसका उपयोग मैंने एक कॉन्फ़िगरेशन ब्लॉक में एक सेवा सम्मिलित करने के लिए किया था, लेकिन यह कुछ समय रहा है। cacheBusterकॉन्फ़िगर फ़ंक्शन के पैरामीटर के रूप में परिभाषित किया गया है। के संबंध में dogmaCacheBusterProvider, यह कुछ चालाक है जिसे एंगुलर ने नामकरण सम्मेलनों के साथ किया है, जिसे मैं लंबे समय से भूल गया हूं। यह आपको करीब ला सकता है, stackoverflow.com/a/20881705/110010
किम 3

इस संदर्भ में। मुझे पता है कि जो भी हम नुस्खा में परिभाषित करते हैं, उस प्रदाता को प्राप्त करते हैं .provider()। क्या होगा अगर मैं किसी चीज को .factory('ServiceName')या .service('ServiceName')रेसिपी के साथ परिभाषित करता हूं और .config ब्लॉक में इसकी किसी एक विधि का उपयोग करना चाहता हूं , तो पैरामीटर को ServiceNameProvider के रूप में सेट करें लेकिन यह मेरे एप्लिकेशन को रोक देता है।
दीचो

5

आप में एक सेवा इंजेक्षन करने के लिए आप $ इंजेक्षन सेवा का उपयोग कर सकते हैं

app.config (समारोह ($ प्रदान) {

    $ provide.decorator ("$ अपवादहैंडलर", फ़ंक्शन ($ प्रतिनिधि, $ इंजेक्टर) {
        वापसी समारोह (अपवाद, कारण) {
            var $ rootScope = $ injector.get ("$ rootScope");
            $ rootScope.addError ({संदेश: "अपवाद", कारण: अपवाद});
            $ प्रतिनिधि (अपवाद, कारण);
        };
    });

});

स्रोत: http://odetocode.com/blogs/scott/archive/2014/04/21/better-error-handling-in-angularjs.aspx


5

** स्पष्ट रूप से अन्य मॉड्यूल से सेवाओं का अनुरोध करें

बस kim3er के उत्तर के बारे में विस्तार से बताने के लिए , आप सेवाओं, कारखानों आदि को प्रदाताओं को बदले बिना प्रदान कर सकते हैं, जब तक कि वे अन्य मॉड्यूल में शामिल नहीं होते हैं ...

हालांकि, मुझे यकीन नहीं है कि अगर *Provider(जो किसी सेवा, या कारखाने को संसाधित करने के बाद कोणीय द्वारा आंतरिक रूप से बनाया गया है) हमेशा उपलब्ध रहेगा (यह पहले क्या लोड किया गया है इस पर निर्भर हो सकता है), कोणीय आलसी लोड मॉड्यूल के रूप में।

ध्यान दें कि यदि आप उन मानों को फिर से इंजेक्ट करना चाहते हैं जिन्हें उन्हें स्थिरांक माना जाना चाहिए।

यहाँ एक और अधिक स्पष्ट है, और शायद यह करने के लिए और अधिक विश्वसनीय तरीका है + काम कर रहे प्लंकर

var base = angular.module('myAppBaseModule', [])
base.factory('Foo', function() { 
  console.log("Foo");
  var Foo = function(name) { this.name = name; };
  Foo.prototype.hello = function() {
    return "Hello from factory instance " + this.name;
  }
  return Foo;
})
base.service('serviceFoo', function() {
  this.hello = function() {
    return "Service says hello";
  }
  return this;
});

var app = angular.module('appModule', []);
app.config(function($provide) {
  var base = angular.injector(['myAppBaseModule']);
  $provide.constant('Foo', base.get('Foo'));
  $provide.constant('serviceFoo', base.get('serviceFoo'));
});
app.controller('appCtrl', function($scope, Foo, serviceFoo) {
  $scope.appHello = (new Foo("app")).hello();
  $scope.serviceHello = serviceFoo.hello();
});

2

कॉन्फ़िगरेशन में सेवा विधियों को कॉल करने के लिए $ इंजेक्टर का उपयोग करना

मेरे पास एक समान मुद्दा था और ऊपर दिखाए अनुसार $ इंजेक्टर सेवा का उपयोग करके इसे हल किया गया था। मैंने सीधे सेवा को इंजेक्ट करने की कोशिश की लेकिन $ http पर एक परिपत्र निर्भरता के साथ समाप्त हो गया। सेवा त्रुटि के साथ एक मोडल प्रदर्शित करती है और मैं ui-बूटस्ट्रैप मोडल का उपयोग कर रहा हूं जिसमें $ https पर निर्भरता भी है।

    $httpProvider.interceptors.push(function($injector) {
    return {
        "responseError": function(response) {

            console.log("Error Response status: " + response.status);

            if (response.status === 0) {
                var myService= $injector.get("myService");
                myService.showError("An unexpected error occurred. Please refresh the page.")
            }
        }
    }

धन्यवाद जिसने बहुत मदद की
इरेज़

2

एक उपाय बहुत आसान है

नोट : यह केवल एक एसिंक्रोन कॉल के लिए है, क्योंकि सेवा कॉन्फ़िगरेशन निष्पादन पर आरंभिक नहीं है।

आप उपयोग कर सकते हैं run() विधि का । उदाहरण :

  1. आपकी सेवा को "MyService" कहा जाता है
  2. आप एक प्रदाता "MyProvider" पर एक एसिंक्रोन निष्पादन के लिए इसका उपयोग करना चाहते हैं

तुम्हारा कोड :

(function () { //To isolate code TO NEVER HAVE A GLOBAL VARIABLE!

    //Store your service into an internal variable
    //It's an internal variable because you have wrapped this code with a (function () { --- })();
    var theServiceToInject = null;

    //Declare your application
    var myApp = angular.module("MyApplication", []);

    //Set configuration
    myApp.config(['MyProvider', function (MyProvider) {
        MyProvider.callMyMethod(function () {
            theServiceToInject.methodOnService();
        });
    }]);

    //When application is initialized inject your service
    myApp.run(['MyService', function (MyService) {
        theServiceToInject = MyService;
    }]);
});

1

खैर, मैंने इस एक के साथ थोड़ा संघर्ष किया, लेकिन मैंने वास्तव में ऐसा किया।

मुझे नहीं पता कि कोणीय में कुछ बदलाव के कारण उत्तर पुराने हैं, लेकिन आप इसे इस तरह से कर सकते हैं:

यह आपकी सेवा है:

.factory('beerRetrievalService', function ($http, $q, $log) {
  return {
    getRandomBeer: function() {
      var deferred = $q.defer();
      var beer = {};

      $http.post('beer-detail', {})
      .then(function(response) {
        beer.beerDetail = response.data;
      },
      function(err) {
        $log.error('Error getting random beer', err);
        deferred.reject({});
      });

      return deferred.promise;
    }
  };
 });

और यह विन्यास है

.when('/beer-detail', {
  templateUrl : '/beer-detail',
  controller  : 'productDetailController',

  resolve: {
    beer: function(beerRetrievalService) {
      return beerRetrievalService.getRandomBeer();
    }
  }
})

0

सबसे आसान उपाय: $injector = angular.element(document.body).injector()

तो चलाने के लिए invoke()या का उपयोग करेंget()


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