AngularJS: एसिंक्रोनस डेटा के साथ प्रारंभिक सेवा


475

मेरे पास एक AngularJS सेवा है जिसे मैं कुछ अतुल्यकालिक डेटा के साथ आरंभ करना चाहता हूं। कुछ इस तरह:

myModule.service('MyService', function($http) {
    var myData = null;

    $http.get('data.json').success(function (data) {
        myData = data;
    });

    return {
        setData: function (data) {
            myData = data;
        },
        doStuff: function () {
            return myData.getSomeData();
        }
    };
});

जाहिर है यह काम नहीं करेगा क्योंकि अगर कुछ वापस आने doStuff()से पहले कॉल करने की कोशिश करता है तो myDataमुझे एक शून्य सूचक अपवाद मिलेगा। जहां तक ​​मैं यहां पूछे गए कुछ अन्य प्रश्नों को पढ़ने से बता सकता हूं और यहां मेरे पास कुछ विकल्प हैं, लेकिन उनमें से कोई भी बहुत साफ नहीं लगता है (शायद मुझे कुछ याद आ रहा है):

"रन" के साथ सेटअप सेवा

मेरा ऐप सेट करते समय ऐसा करें:

myApp.run(function ($http, MyService) {
    $http.get('data.json').success(function (data) {
        MyService.setData(data);
    });
});

तब मेरी सेवा इस तरह दिखाई देगी:

myModule.service('MyService', function() {
    var myData = null;
    return {
        setData: function (data) {
            myData = data;
        },
        doStuff: function () {
            return myData.getSomeData();
        }
    };
});

यह कुछ समय के लिए काम करता है लेकिन अगर एसिंक्रोनस डेटा को होने में अधिक समय लगता है तो इसे शुरू करने के लिए मुझे सब कुछ लेना पड़ता है जब मैं कॉल करता हूं तो मुझे एक शून्य सूचक अपवाद मिलता है doStuff()

वादा वस्तुओं का उपयोग करें

यह शायद काम करेगा। केवल हर जगह यह उल्टा है कि मैं MyService को कॉल करता हूं मुझे यह जानना होगा कि doStuff () एक वादा वापस करता है और सभी कोड को thenवादे के साथ बातचीत करने के लिए हमें करना होगा । मैं बजाय अपने आवेदन लोड करने से पहले myData वापस आने तक इंतजार करना होगा।

मैनुअल बूटस्ट्रैप

angular.element(document).ready(function() {
    $.getJSON("data.json", function (data) {
       // can't initialize the data here because the service doesn't exist yet
       angular.bootstrap(document);
       // too late to initialize here because something may have already
       // tried to call doStuff() and would have got a null pointer exception
    });
});

वैश्विक जावास्क्रिप्ट वार I अपने JSON को सीधे एक वैश्विक जावास्क्रिप्ट चर में भेज सकता है:

HTML:

<script type="text/javascript" src="data.js"></script>

data.js:

var dataForMyService = { 
// myData here
};

तब यह तब उपलब्ध होगा जब आरंभीकरण MyService:

myModule.service('MyService', function() {
    var myData = dataForMyService;
    return {
        doStuff: function () {
            return myData.getSomeData();
        }
    };
});

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

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


कोणीय - बूटस्ट्रैप एसिंक्रोनस रूप से एक सर्वर से डेटा खींचने के लिए कोड के माध्यम से चलता है $http, फिर एक सेवा में डेटा को सहेजता है, फिर एक ऐप को बूटस्ट्रैप करता है।
स्टीवन वेक्सलर

जवाबों:


327

क्या आपकी नज़र इस पर पड़ी है $routeProvider.when('/path',{ resolve:{...}? यह वादा दृष्टिकोण थोड़ा साफ कर सकता है:

अपनी सेवा में एक वादा उजागर करें:

app.service('MyService', function($http) {
    var myData = null;

    var promise = $http.get('data.json').success(function (data) {
      myData = data;
    });

    return {
      promise:promise,
      setData: function (data) {
          myData = data;
      },
      doStuff: function () {
          return myData;//.getSomeData();
      }
    };
});

resolveअपने रूट कॉन्‍फ़िगर में जोड़ें :

app.config(function($routeProvider){
  $routeProvider
    .when('/',{controller:'MainCtrl',
    template:'<div>From MyService:<pre>{{data | json}}</pre></div>',
    resolve:{
      'MyServiceData':function(MyService){
        // MyServiceData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service
        return MyService.promise;
      }
    }})
  }):

सभी निर्भरताएँ हल होने से पहले आपका नियंत्रक तुरंत नहीं मिलेगा:

app.controller('MainCtrl', function($scope,MyService) {
  console.log('Promise is now resolved: '+MyService.doStuff().data)
  $scope.data = MyService.doStuff();
});

मैंने plnkr पर एक उदाहरण बनाया है: http://plnkr.co/edit/GKg21XH0RwCMEQGUdZKH?p=preview


1
आपकी प्रतिक्रिया के लिए बहुत बहुत धन्यवाद! यह मेरे लिए काम करेगा अगर मेरे पास पहले से ही संकल्प मानचित्र में एक सेवा नहीं है जो MyService का उपयोग करता है। मैंने आपकी स्थिति के साथ आपका प्लंकर अपडेट किया: plnkr.co/edit/465Cupaf5mtxljCl5NuF?p=preview । वहाँ किसी भी तरह से MyOtherService MyService के लिए प्रतीक्षा कर रहा है आरंभ करने के लिए है?
13 दिसंबर को परीक्षण123

2
मुझे लगता है कि मैं MyOtherService में वादों की श्रृंखला बनाऊंगा - मैंने प्लंकर को चेनिंग और कुछ टिप्पणियों के साथ अपडेट किया है - यह कैसे दिखता है? plnkr.co/edit/Z7dWVNA9P44Q72sLiPjW?p=preview
joakimbl

3
मैंने इसे आज़माया और फिर भी कुछ मुद्दों में भाग गया क्योंकि मेरे पास निर्देश और अन्य नियंत्रक हैं (नियंत्रक मैं $ मार्ग के साथ उपयोग करता हूं। Piderider एक प्राथमिक, द्वितीयक नेविगेशन सामान को संभाल रहा है ... यह 'MyOtherService' है) जिसे MyService तक इंतजार करना होगा। ' सुलझ गया है। मैं कोशिश करता रहूंगा और मेरे पास मौजूद किसी भी सफलता के साथ इसे अपडेट करूंगा। मैं बस चाहता हूं कि कोणीय में एक हुक था जहां मैं अपने नियंत्रकों और निर्देशों को शुरू करने से पहले डेटा के वापस आने का इंतजार कर सकता था। आपकी सहायता के लिए एक बार फिर से धन्यवाद। अगर मेरे पास एक मुख्य नियंत्रक है जो सब कुछ लपेटता है तो यह काम करेगा।
परीक्षण १२

43
यहां एक प्रश्न - आप resolveकिसी नियंत्रक को संपत्ति कैसे निर्दिष्ट करेंगे जो इसमें उल्लिखित नहीं है $routeProvider। उदाहरण के लिए, <div ng-controller="IndexCtrl"></div>। यहां, नियंत्रक को स्पष्ट रूप से उल्लेख किया गया है और रूटिंग के माध्यम से लोड नहीं किया गया है। ऐसे मामले में, कोई तब नियंत्रक की त्वरित देरी क्यों करेगा?
callmekatootie

19
यदि आप रूटिंग का उपयोग नहीं कर रहे हैं तो क्या है? यह लगभग ऐसा है जैसे आप अतुल्यकालिक डेटा के साथ एक कोणीय ऐप नहीं लिख सकते हैं जब तक कि आप रूटिंग का उपयोग न करें। किसी ऐप में डेटा प्राप्त करने के लिए अनुशंसित तरीका इसे अतुल्यकालिक रूप से लोड करना है, लेकिन जैसे ही आपके पास एक से अधिक नियंत्रक हैं और आप सेवाओं में फेंकते हैं, बूम यह असंभव है।
वायर्ड_इन

88

मार्टिन एटकिन्स के समाधान पर आधारित, यहाँ एक पूर्ण, संक्षिप्त शुद्ध-कोणीय समाधान है:

(function() {
  var initInjector = angular.injector(['ng']);
  var $http = initInjector.get('$http');
  $http.get('/config.json').then(
    function (response) {
      angular.module('config', []).constant('CONFIG', response.data);

      angular.element(document).ready(function() {
          angular.bootstrap(document, ['myApp']);
        });
    }
  );
})();

यह समाधान $ http सेवा प्राप्त करने के लिए एक स्व-निष्पादित अनाम फ़ंक्शन का उपयोग करता है, कॉन्फ़िगरेशन का अनुरोध करता है, और उपलब्ध होने पर इसे CONFIG नामक स्थिरांक में इंजेक्ट करता है।

एक बार पूरी तरह से, हम तब तक इंतजार करते हैं जब तक कि दस्तावेज़ तैयार नहीं हो जाता है और फिर कोणीय ऐप को बूटस्ट्रैप कर देता है।

यह मार्टिन के समाधान पर एक मामूली वृद्धि है, जिसने दस्तावेज़ तैयार होने के बाद तक कॉन्फ़िगरेशन को स्थगित कर दिया। जहाँ तक मुझे पता है, उसके लिए $ http कॉल में देरी का कोई कारण नहीं है।

इकाई का परीक्षण

नोट: मुझे पता चला है कि जब आपकी app.jsफाइल में कोड को शामिल किया जाता है तो यह समाधान अच्छी तरह से काम नहीं करता है । इसका कारण यह है कि जेएस फ़ाइल लोड होने पर उपरोक्त कोड तुरंत चलता है। इसका मतलब यह है कि परीक्षण रूपरेखा (मेरे मामले में जैस्मिन) के पास एक नकली कार्यान्वयन प्रदान करने का मौका नहीं है $http

मेरा समाधान, जिसे मैं पूरी तरह से संतुष्ट नहीं हूं, इस कोड को हमारी index.htmlफ़ाइल में स्थानांतरित करना था , इसलिए ग्रंट / कर्मा / जैस्मीन यूनिट टेस्ट इन्फ्रास्ट्रक्चर इसे नहीं देखता है।


1
नियम जैसे कि 'वैश्विक दायरे को प्रदूषित न करें' का पालन केवल उस सीमा तक किया जाना चाहिए, जब तक वे हमारे कोड को बेहतर (कम जटिल, अधिक रख-रखाव, अधिक सुरक्षित आदि) बना देते हैं। मैं यह नहीं देख सकता कि यह समाधान केवल एकल वैश्विक चर में डेटा लोड करने से बेहतर कैसे है। मैं क्या खो रहा हूँ?
david004

4
यह आपको उन मॉड्यूल में 'CONFIG' कंटीन्यू को एक्सेस करने के लिए कोणीय की निर्भरता इंजेक्शन प्रणाली का उपयोग करने की अनुमति देता है, लेकिन आप अन्य मॉड्यूल को क्लोबबेरिंग नहीं करने का जोखिम नहीं उठाते हैं। उदाहरण के लिए, यदि आपने एक वैश्विक 'कॉन्फिगरेशन' वैरिएबल का उपयोग किया है, तो एक मौका है कि अन्य 3 पार्टी कोड भी उसी वैरिएबल की तलाश में हैं।
JBCP

1
मैं एक कोणीय नौसिखिया हूं, यहां कुछ नोट्स दिए गए हैं कि मुझे अपने ऐप में कॉन्फिग मॉड्यूल निर्भरता का समाधान कैसे मिला: gist.github.com/dsulli99/0be3e80db9b21ce7b989 रेफरी: tutorials.jindkov.com/angularjs/… इस समाधान के लिए धन्यवाद।
डीपीएस

7
यह नीचे दिए गए अन्य मैनुअल बूटस्ट्रैप समाधानों में से एक में एक टिप्पणी में उल्लेख किया गया है, लेकिन एक कोणीय नौसिखिया के रूप में जो इसे स्थान नहीं देता है, मैं सिर्फ यह इंगित कर सकता हूं कि आपको ठीक से काम करने के लिए अपने html कोड में अपने एनजी-ऐप निर्देश को हटाने की आवश्यकता है - यह इस मैनुअल विधि के साथ स्वचालित बूटस्ट्रैप (एनजी-एप के माध्यम से) की जगह ले रहा है। यदि आप एनजी-ऐप को बाहर नहीं निकालते हैं, तो अनुप्रयोग वास्तव में काम कर सकता है लेकिन आपको कंसोल में विभिन्न अज्ञात प्रदाताओं की त्रुटियां दिखाई देंगी।
आयरिशडबग्यू

49

मैंने @XMLilley द्वारा वर्णित एक समान दृष्टिकोण का उपयोग किया, लेकिन एंगुलरजेएस सेवाओं का उपयोग करने की क्षमता को $httpकॉन्फ़िगरेशन को लोड करने और निम्न स्तर के एपीआई या jQuery के उपयोग के बिना आगे आरंभ करने के लिए पसंद करना चाहता था ।

resolveमार्गों पर उपयोग करना भी एक विकल्प नहीं था क्योंकि मुझे मेरी ऐप शुरू होने पर, यहां तक ​​कि module.config()ब्लॉकों में भी स्थिरांक के रूप में उपलब्ध मूल्यों की आवश्यकता थी ।

मैंने एक छोटा AngularJS ऐप बनाया, जो कॉन्फिगरेशन को लोड करता है, उन्हें वास्तविक ऐप पर कॉन्स्टेंट के रूप में सेट करता है और इसे बूटस्ट्रैप करता है।

// define the module of your app
angular.module('MyApp', []);

// define the module of the bootstrap app
var bootstrapModule = angular.module('bootstrapModule', []);

// the bootstrapper service loads the config and bootstraps the specified app
bootstrapModule.factory('bootstrapper', function ($http, $log, $q) {
  return {
    bootstrap: function (appName) {
      var deferred = $q.defer();

      $http.get('/some/url')
        .success(function (config) {
          // set all returned values as constants on the app...
          var myApp = angular.module(appName);
          angular.forEach(config, function(value, key){
            myApp.constant(key, value);
          });
          // ...and bootstrap the actual app.
          angular.bootstrap(document, [appName]);
          deferred.resolve();
        })
        .error(function () {
          $log.warn('Could not initialize application, configuration could not be loaded.');
          deferred.reject();
        });

      return deferred.promise;
    }
  };
});

// create a div which is used as the root of the bootstrap app
var appContainer = document.createElement('div');

// in run() function you can now use the bootstrapper service and shutdown the bootstrapping app after initialization of your actual app
bootstrapModule.run(function (bootstrapper) {

  bootstrapper.bootstrap('MyApp').then(function () {
    // removing the container will destroy the bootstrap app
    appContainer.remove();
  });

});

// make sure the DOM is fully loaded before bootstrapping.
angular.element(document).ready(function() {
  angular.bootstrap(appContainer, ['bootstrapModule']);
});

इसे यहां देखें ( $timeoutइसके बजाय $http) का उपयोग करते हुए : http://plnkr.co/edit/FYznxP3xe8dxzwxs37hi?p=preview

अपडेट करें

मैं मार्टिन एटकिन्स और जेबीसीपी द्वारा नीचे वर्णित दृष्टिकोण का उपयोग करने की सिफारिश करूंगा।

अद्यतन २

क्योंकि मुझे कई परियोजनाओं में इसकी आवश्यकता थी, मैंने अभी एक बोवर मॉड्यूल जारी किया जो इस बात का ध्यान रखता है: https://github.com/philippd/angular-deferred-bootstrap

उदाहरण जो बैक-एंड से डेटा लोड करता है और AngularJS मॉड्यूल पर APP_CONFIG नामक एक स्थिरांक सेट करता है:

deferredBootstrapper.bootstrap({
  element: document.body,
  module: 'MyApp',
  resolve: {
    APP_CONFIG: function ($http) {
      return $http.get('/api/demo-config');
    }
  }
});

11
deferredBootstrapper जाने का रास्ता है
fatlinesofcode

44

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

angular.element(document).ready(
    function() {
        var initInjector = angular.injector(['ng']);
        var $http = initInjector.get('$http');
        $http.get('/config.json').then(
            function (response) {
               var config = response.data;
               // Add additional services/constants/variables to your app,
               // and then finally bootstrap it:
               angular.bootstrap(document, ['myApp']);
            }
        );
    }
);

उदाहरण के लिए, आप module.constantअपने ऐप को डेटा उपलब्ध कराने के लिए तंत्र का उपयोग कर सकते हैं :

myApp.constant('myAppConfig', data);

यह myAppConfigअब किसी भी अन्य सेवा इंजेक्ट किया जा सकता है, और विशेष रूप से यह विन्यास चरण के दौरान उपलब्ध है:

myApp.config(
    function (myAppConfig, someService) {
        someService.config(myAppConfig.someServiceConfig);
    }
);

या, एक छोटे से ऐप के लिए, आप पूरे एप्लिकेशन में कॉन्फ़िगरेशन प्रारूप के बारे में ज्ञान फैलाने की कीमत पर, सीधे अपनी सेवा में वैश्विक कॉन्फ़िगरेशन को इंजेक्ट कर सकते हैं।

बेशक, चूंकि यहां async ऑपरेशंस एप्लिकेशन के बूटस्ट्रैप को ब्लॉक कर देगा, और इस तरह टेम्पलेट के संकलन / लिंकिंग को ब्लॉक कर देगा, इसलिए यह ng-cloakअनपेक्षित टेम्पलेट को काम के दौरान दिखाने से रोकने के लिए निर्देश का उपयोग करने के लिए बुद्धिमान है । आप DOM में कुछ संकेत लोड करने का संकेत भी दे सकते हैं, कुछ HTML प्रदान करके जो केवल तब तक दिखाया जाता है जब तक AngularJS आरंभ नहीं कर देता:

<div ng-if="initialLoad">
    <!-- initialLoad never gets set, so this div vanishes as soon as Angular is done compiling -->
    <p>Loading the app.....</p>
</div>
<div ng-cloak>
    <!-- ng-cloak attribute is removed once the app is done bootstrapping -->
    <p>Done loading the app!</p>
</div>

मैंने प्लंकर पर इस दृष्टिकोण का एक पूर्ण, काम करने वाला उदाहरण बनाया , एक उदाहरण के रूप में एक स्थिर JSON फ़ाइल से कॉन्फ़िगरेशन लोड करना।


मुझे नहीं लगता कि दस्तावेज़ तैयार होने के बाद आपको $ http.get () को स्थगित करने की आवश्यकता है।
JBCP

@JBCP हाँ, आप सही कह रहे हैं कि यह ठीक वैसे ही काम करता है जैसे आप घटनाओं को स्वैप करते हैं ताकि हम तब तक तैयार न हो जाएँ जब तक कि HTTP रिस्पॉन्स वापस न हो जाए, तब तक आप तैयार रहें जब तक कि HTTP शुरू करने में सक्षम न हो। तेजी से अनुरोध करें। DOM तैयार होने तक केवल बूटस्ट्रैप कॉल की प्रतीक्षा करनी होगी।
मार्टिन एटकिन्स

2
मैंने आपके दृष्टिकोण के साथ एक बोवर मॉड्यूल बनाया: github.com/philippd/angular-deferred-bootstrap
philippd

@MartinAtkins, मैंने अभी-अभी पाया कि आपका महान दृष्टिकोण Angular v1.1 + के साथ काम नहीं करता है। यह एंगुलर के शुरुआती संस्करणों की तरह लगता है, तब तक "तब" समझ में नहीं आता जब तक कि आवेदन को बूटस्ट्रैप नहीं किया जाता है। अपने प्लंक
vkelman 15

16

मुझे एक ही समस्या थी: मैं resolveऑब्जेक्ट को प्यार करता हूं , लेकिन यह केवल एनजी-व्यू की सामग्री के लिए काम करता है। क्या होगा यदि आपके पास नियंत्रक हैं (शीर्ष-स्तरीय नौसेना के लिए, मान लें कि) एनजी-व्यू के बाहर मौजूद हैं और जिन्हें रूट करने से पहले डेटा के साथ आरंभीकृत होने की आवश्यकता है? कैसे हम उस काम को करने के लिए सर्वर-साइड पर चक्कर लगाने से बचते हैं?

मैनुअल बूटस्ट्रैप और कोणीय स्थिरांक का उपयोग करें । एक niveive XHR आपको अपना डेटा देता है, और आप इसके कॉलबैक में कोणीय बूट करते हैं, जो आपके async मुद्दों से संबंधित है। नीचे दिए गए उदाहरण में, आपको वैश्विक वैरिएबल बनाने की भी आवश्यकता नहीं है। लौटाया गया डेटा केवल कोणीय दायरे में एक इंजेक्शन के रूप में मौजूद है, और जब तक आप इसे इंजेक्ट नहीं करते हैं, तब तक यह नियंत्रकों, सेवाओं आदि के अंदर मौजूद नहीं होता है। (जितना आप अपने आउटपुट को इंजेक्ट करेंगेresolve रूट किए गए दृश्य के लिए नियंत्रक में वस्तु ।) यदि आप उस डेटा के साथ एक सेवा के रूप में बातचीत करना पसंद करते हैं, तो आप एक सेवा बना सकते हैं, डेटा को इंजेक्ट कर सकते हैं, और कोई भी कभी भी समझदार नहीं होगा। ।

उदाहरण:

//First, we have to create the angular module, because all the other JS files are going to load while we're getting data and bootstrapping, and they need to be able to attach to it.
var MyApp = angular.module('MyApp', ['dependency1', 'dependency2']);

// Use angular's version of document.ready() just to make extra-sure DOM is fully 
// loaded before you bootstrap. This is probably optional, given that the async 
// data call will probably take significantly longer than DOM load. YMMV.
// Has the added virtue of keeping your XHR junk out of global scope. 
angular.element(document).ready(function() {

    //first, we create the callback that will fire after the data is down
    function xhrCallback() {
        var myData = this.responseText; // the XHR output

        // here's where we attach a constant containing the API data to our app 
        // module. Don't forget to parse JSON, which `$http` normally does for you.
        MyApp.constant('NavData', JSON.parse(myData));

        // now, perform any other final configuration of your angular module.
        MyApp.config(['$routeProvider', function ($routeProvider) {
            $routeProvider
              .when('/someroute', {configs})
              .otherwise({redirectTo: '/someroute'});
          }]);

        // And last, bootstrap the app. Be sure to remove `ng-app` from your index.html.
        angular.bootstrap(document, ['NYSP']);
    };

    //here, the basic mechanics of the XHR, which you can customize.
    var oReq = new XMLHttpRequest();
    oReq.onload = xhrCallback;
    oReq.open("get", "/api/overview", true); // your specific API URL
    oReq.send();
})

अब, आपका NavDataनिरंतर अस्तित्व है। आगे बढ़ो और इसे एक नियंत्रक या सेवा में इंजेक्ट करें:

angular.module('MyApp')
    .controller('NavCtrl', ['NavData', function (NavData) {
        $scope.localObject = NavData; //now it's addressable in your templates 
}]);

बेशक, एक नंगे एक्सएचआर ऑब्जेक्ट का उपयोग करके ऐसी कई बारीकियों को दूर किया जाता है, जो $httpया JQuery आपके लिए देखभाल करेगा, लेकिन यह उदाहरण बिना किसी विशेष निर्भरता के काम करता है, कम से कम एक साधारण के लिए get। यदि आप अपने अनुरोध के लिए थोड़ी अधिक शक्ति चाहते हैं, तो बाहरी पुस्तकालय को आपकी सहायता के लिए लोड करें। लेकिन मुझे नहीं लगता कि $httpइस संदर्भ में कोणीय या अन्य उपकरणों का उपयोग करना संभव है ।

(एसओ संबंधित पोस्ट )


8

आप जो कुछ भी कर सकते हैं वह ऐप के लिए .config में मार्ग के लिए रिज़ॉल्यूशन ऑब्जेक्ट और $ q में फ़ंक्शन पास (वादा ऑब्जेक्ट) और आपके द्वारा निर्भर की जाने वाली सेवा का नाम है, और वादे को हल करने के लिए है। इस तरह से सेवा में $ http के लिए कॉलबैक फ़ंक्शन:

रूट कॉन्फिग

app.config(function($routeProvider){
    $routeProvider
     .when('/',{
          templateUrl: 'home.html',
          controller: 'homeCtrl',
          resolve:function($q,MyService) {
                //create the defer variable and pass it to our service
                var defer = $q.defer();
                MyService.fetchData(defer);
                //this will only return when the promise
                //has been resolved. MyService is going to
                //do that for us
                return defer.promise;
          }
      })
}

कोणीय को टेम्प्लेट रेंडर नहीं करेगा या नियंत्रक को तब तक उपलब्ध नहीं कराएगा जब तक कि defer.resolve () को कॉल नहीं किया गया हो। हम अपनी सेवा में ऐसा कर सकते हैं:

सर्विस

app.service('MyService',function($http){
       var MyService = {};
       //our service accepts a promise object which 
       //it will resolve on behalf of the calling function
       MyService.fetchData = function(q) {
             $http({method:'GET',url:'data.php'}).success(function(data){
                 MyService.data = data;
                 //when the following is called it will
                 //release the calling function. in this
                 //case it's the resolve function in our
                 //route config
                 q.resolve();
             }
       }

       return MyService;
});

अब जब MyService के पास यह डेटा प्रॉपर्टी को सौंपा गया डेटा है, और रूट सॉल्यूशन ऑब्जेक्ट में वादा किया गया है, रूट के लिए हमारा कंट्रोलर जीवन में किक मारता है, और हम सर्विस से डेटा को अपने कंट्रोलर ऑब्जेक्ट को असाइन कर सकते हैं।

नियंत्रक

  app.controller('homeCtrl',function($scope,MyService){
       $scope.servicedata = MyService.data;
  });

अब नियंत्रक के दायरे में हमारे सभी बाध्यकारी डेटा का उपयोग करने में सक्षम होंगे जो MyService से उत्पन्न हुआ था।


अधिक समय होने पर मैं इसे एक शॉट दूंगा। यह वैसा ही दिखता है जैसा दूसरे लोग ngModules में करने की कोशिश कर रहे थे।
परीक्षण123

1
मुझे यह दृष्टिकोण पसंद है और मैंने इसे पहले भी इस्तेमाल किया है लेकिन मैं वर्तमान में यह जानने की कोशिश कर रहा हूं कि जब मेरे पास कई मार्ग हैं, तो मैं इसे साफ तरीके से कैसे कर सकता हूं, जिनमें से प्रत्येक पूर्वनिर्मित डेटा पर निर्भर हो सकता है या नहीं। उस पर कोई विचार?
ivarni

btw, मैं इस बात की ओर झुकाव कर रहा हूं कि प्रत्येक सेवा के लिए आवश्यक है कि प्रीफ़ेट किए गए डेटा के लिए अनुरोध किया जाए जब इसे आरंभीकृत किया जाए और एक वादा वापस किया जाए और फिर विभिन्न मार्गों द्वारा आवश्यक सेवाओं के साथ संकल्प-ऑब्जेक्ट सेट करें। मैं बस चाहता हूं कि एक कम क्रिया तरीका था।
ivarni

1
@dewd यह वही है जिसके लिए मैं लक्ष्य बना रहा था, लेकिन मैं बहुत पसंद करूंगा यदि कोई रास्ता हो तो बस यह कहो कि "मेरे रूट के ब्लॉक को दोहराने के बिना" यह सब सामान पहले लाएं चाहे जो भी रूट लोड किया गया हो "। वे सब कुछ वे पर निर्भर है। लेकिन यह बहुत बड़ी बात नहीं है, यह सिर्फ थोड़ा अधिक महसूस होगा :)
ivarni

2
यह वह मार्ग है जिसे मैंने समाप्त कर दिया है, सिवाय इसके कि मुझे resolveएक संपत्ति के साथ एक फ़ंक्शन बनाना है। इसलिए यह समाप्त हो गयाresolve:{ dataFetch: function(){ // call function here } }
aron.duby

5

तो मुझे एक उपाय मिला। मैंने एक angularJS सेवा बनाई है, हम इसे MyDataRepository कहेंगे और मैंने इसके लिए एक मॉड्यूल बनाया। मैं तब अपने सर्वर-साइड कंट्रोलर से इस जावास्क्रिप्ट फ़ाइल की सेवा करता हूं:

HTML:

<script src="path/myData.js"></script>

सर्वर साइड:

@RequestMapping(value="path/myData.js", method=RequestMethod.GET)
public ResponseEntity<String> getMyDataRepositoryJS()
{
    // Populate data that I need into a Map
    Map<String, String> myData = new HashMap<String,String>();
    ...
    // Use Jackson to convert it to JSON
    ObjectMapper mapper = new ObjectMapper();
    String myDataStr = mapper.writeValueAsString(myData);

    // Then create a String that is my javascript file
    String myJS = "'use strict';" +
    "(function() {" +
    "var myDataModule = angular.module('myApp.myData', []);" +
    "myDataModule.service('MyDataRepository', function() {" +
        "var myData = "+myDataStr+";" +
        "return {" +
            "getData: function () {" +
                "return myData;" +
            "}" +
        "}" +
    "});" +
    "})();"

    // Now send it to the client:
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.add("Content-Type", "text/javascript");
    return new ResponseEntity<String>(myJS , responseHeaders, HttpStatus.OK);
}

मैं तब MyDataRepository को इंजेक्ट कर सकता हूं जहां कभी भी मुझे इसकी आवश्यकता होती है:

someOtherModule.service('MyOtherService', function(MyDataRepository) {
    var myData = MyDataRepository.getData();
    // Do what you have to do...
}

इसने मेरे लिए बहुत अच्छा काम किया, लेकिन अगर किसी के पास कोई प्रतिक्रिया है तो मैं इसके लिए खुला हूं। }


मुझे आपका मॉड्यूलर अप्रोच पसंद है। मैंने पाया है कि $ pathScope डेटा का अनुरोध करने वाली सेवा के लिए उपलब्ध है और आप $ http.success कॉलबैक में इसे डेटा असाइन कर सकते हैं। हालांकि, गैर-वैश्विक वस्तुओं के लिए $ मार्गस्कोप का उपयोग करने से एक गंध पैदा होती है और डेटा को वास्तव में नियंत्रक $ गुंजाइश को सौंपा जाना चाहिए। दुर्भाग्य से, मुझे लगता है कि आपका दृष्टिकोण, अभिनव होने के बावजूद, आदर्श नहीं है (हालांकि कुछ खोजने के लिए सम्मान जो आपके लिए काम करता है)। मुझे यकीन है कि एक क्लाइंट-साइड केवल उत्तर होना चाहिए जो किसी तरह डेटा का इंतजार करता है और असाइनमेंट को स्कोप की अनुमति देता है। खोज जारी है!
'18

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

2

इसके अलावा, वास्तविक नियंत्रकों द्वारा निष्पादित किए जाने से पहले, आप विश्व स्तर पर अपनी सेवा का प्रबंधन करने के लिए निम्नलिखित तकनीकों का उपयोग कर सकते हैं: https://stackoverflow.com/a/27050497/1056679 । बस अपने डेटा को विश्व स्तर पर हल करें और फिर runउदाहरण के लिए इसे अपनी सेवा में ब्लॉक करें।


1

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

आप html इस तरह दिखेंगे:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>

function MyService {
  this.getData = function(){
    return   MyService.data;
  }
}
MyService.setData = function(data) {
  MyService.data = data;
}

angular.module('main')
.service('MyService', MyService)

</script>
<script src="/some_data.php?jsonp=MyService.setData"></script>

-1

किसी भी आरंभिक उपयोग एनजी-इनिट निर्देशिका को लाने का सबसे आसान तरीका।

जहां आप init डेटा लाना चाहते हैं, वहां एनजी-इनिट डिव गुंजाइश डालें

index.html

<div class="frame" ng-init="init()">
    <div class="bit-1">
      <div class="field p-r">
        <label ng-show="regi_step2.address" class="show-hide c-t-1 ng-hide" style="">Country</label>
        <select class="form-control w-100" ng-model="country" name="country" id="country" ng-options="item.name for item in countries" ng-change="stateChanged()" >
        </select>
        <textarea class="form-control w-100" ng-model="regi_step2.address" placeholder="Address" name="address" id="address" ng-required="true" style=""></textarea>
      </div>
    </div>
  </div>

index.js

$scope.init=function(){
    $http({method:'GET',url:'/countries/countries.json'}).success(function(data){
      alert();
           $scope.countries = data;
    });
  };

नोट: आप इस पद्धति का उपयोग कर सकते हैं यदि आपके पास एक ही कोड अधिक नहीं है तो एक जगह।


डॉक्स के अनुसार ngInit का उपयोग करने की सलाह नहीं दी गई है: docs.angularjs.org/api/ng/directive/ngInit
fodma1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.