AngularJS: Inisialisasi layanan dengan data tidak sinkron

475

Saya memiliki layanan AngularJS yang ingin saya inisialisasi dengan beberapa data asinkron. Sesuatu seperti ini:

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();
        }
    };
});

Jelas ini tidak akan berhasil karena jika sesuatu mencoba menelepon doStuff()sebelum myDatakembali saya akan mendapatkan pengecualian null pointer. Sejauh yang saya tahu dari membaca beberapa pertanyaan lain yang diajukan di sini dan di sini saya punya beberapa pilihan, tetapi tidak ada yang tampak sangat bersih (mungkin saya kehilangan sesuatu):

Setup Service dengan "run"

Saat menyiapkan aplikasi saya lakukan ini:

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

Maka layanan saya akan terlihat seperti ini:

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

Ini berfungsi beberapa waktu tetapi jika data asinkron terjadi lebih lama dari yang dibutuhkan untuk semuanya untuk diinisialisasi, saya mendapatkan pengecualian null pointer ketika saya menelepon doStuff()

Gunakan benda janji

Ini mungkin akan berhasil. Satu-satunya downside di mana-mana saya sebut MyService saya harus tahu bahwa doStuff () mengembalikan janji dan semua kode harus kita thenuntuk berinteraksi dengan janji itu. Saya lebih suka menunggu sampai myData kembali sebelum memuat aplikasi saya.

Bootstrap Manual

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
    });
});

Global Javascript Var Saya bisa mengirim JSON saya langsung ke variabel Javascript global:

HTML:

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

data.js:

var dataForMyService = { 
// myData here
};

Maka akan tersedia saat menginisialisasi MyService:

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

Ini akan berhasil juga, tetapi kemudian saya memiliki variabel javascript global yang baunya buruk.

Apakah ini satu-satunya pilihan saya? Apakah salah satu opsi ini lebih baik daripada yang lain? Saya tahu ini adalah pertanyaan yang cukup panjang, tetapi saya ingin menunjukkan bahwa saya telah mencoba mengeksplorasi semua opsi saya. Bimbingan apa pun akan sangat dihargai.

testing123
sumber
angular - bootstrap berjalan secara tidak sinkron melalui kode untuk menarik data dari server dengan $http, lalu menyimpan data dalam suatu layanan, lalu mem-bootstrap aplikasi.
Steven Wexler

Jawaban:

327

Apakah Anda sudah melihatnya $routeProvider.when('/path',{ resolve:{...}? Itu bisa membuat pendekatan janji sedikit lebih bersih:

Paparkan janji dalam layanan Anda:

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();
      }
    };
});

Tambahkan resolveke konfigurasi rute Anda:

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;
      }
    }})
  }):

Pengontrol Anda tidak akan instantiasi sebelum semua dependensi diselesaikan:

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

Saya telah membuat contoh di plnkr: http://plnkr.co/edit/GKg21XH0RwCMEQGUdZKH?p=preview

joakimbl
sumber
1
Terima kasih banyak atas tanggapan Anda! Ini akan bekerja untuk saya jika saya belum memiliki layanan di peta tekad yang menggunakan MyService. Saya memperbarui plunker Anda dengan situasi saya: plnkr.co/edit/465Cupaf5mtxljCl5NuF?p=preview . Apakah ada cara membuat MyOtherService menunggu MyService untuk diinisialisasi?
testing123
2
Saya kira saya akan rantai janji-janji di MyOtherService - Saya telah memperbarui plunker dengan rantai dan beberapa komentar - bagaimana ini terlihat? plnkr.co/edit/Z7dWVNA9P44Q72sLiPjW?p=preview
joakimbl
3
Saya mencoba ini dan masih mengalami beberapa masalah karena saya memiliki arahan dan pengontrol lain (controller yang saya gunakan dengan $ routeProvider menangani hal-hal utama, navigasi sekunder ... yaitu 'MyOtherService') yang perlu menunggu sampai 'MyService ' terselesaikan. Saya akan terus mencoba dan memperbarui ini dengan kesuksesan yang saya miliki. Saya hanya berharap ada kait di sudut di mana saya bisa menunggu data kembali sebelum menginisialisasi pengendali dan arahan saya. Sekali lagi terima kasih atas bantuan Anda. Jika saya memiliki pengontrol utama yang membungkus semuanya ini akan berhasil.
testing123
43
Sebuah pertanyaan di sini - bagaimana Anda akan menetapkan resolveproperti ke controller yang tidak disebutkan dalam $routeProvider. Sebagai contoh <div ng-controller="IndexCtrl"></div>,. Di sini, pengontrol disebutkan secara eksplisit dan tidak dimuat melalui perutean. Dalam kasus seperti itu, bagaimana mungkin seseorang menunda instantiation dari controller itu?
callmekatootie
19
Ummm bagaimana jika Anda tidak menggunakan perutean? Ini hampir seperti mengatakan Anda tidak dapat menulis aplikasi bersudut dengan data asinkron kecuali Anda menggunakan perutean. Cara yang disarankan untuk memasukkan data ke aplikasi adalah dengan memuatnya secara tidak sinkron, tetapi begitu Anda memiliki lebih dari satu pengontrol dan Anda memberikan layanan, BOOM tidak mungkin.
wired_in
88

Berdasarkan solusi Martin Atkins, berikut ini adalah solusi Angular murni lengkap dan ringkas:

(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']);
        });
    }
  );
})();

Solusi ini menggunakan fungsi anonim yang dijalankan sendiri untuk mendapatkan layanan $ http, meminta konfigurasi, dan menyuntikkannya ke dalam konstanta yang disebut CONFIG saat tersedia.

Setelah sepenuhnya, kami menunggu hingga dokumen siap dan kemudian bootstrap aplikasi Angular.

Ini sedikit peningkatan dari solusi Martin, yang ditangguhkan mengambil konfigurasi sampai setelah dokumen siap. Sejauh yang saya tahu, tidak ada alasan untuk menunda panggilan $ http untuk itu.

Pengujian Unit

Catatan: Saya menemukan solusi ini tidak berfungsi dengan baik ketika unit-testing ketika kode dimasukkan dalam app.jsfile Anda . Alasan untuk ini adalah bahwa kode di atas berjalan segera ketika file JS dimuat. Ini berarti kerangka uji (Jasmine dalam kasus saya) tidak memiliki kesempatan untuk memberikan implementasi tiruan $http.

Solusi saya, yang saya tidak sepenuhnya puas dengan, adalah memindahkan kode ini ke index.htmlfile kami , sehingga infrastruktur uji unit Grunt / Karma / Jasmine tidak melihatnya.

JBCP
sumber
1
Aturan seperti 'jangan mencemari lingkup global' harus diikuti hanya sejauh mereka membuat kode kita lebih baik (kurang kompleks, lebih dapat dikelola, lebih aman, dll). Saya tidak bisa melihat bagaimana solusi ini lebih baik daripada hanya memuat data ke dalam variabel global tunggal. Apa yang saya lewatkan?
david004
4
Ini memungkinkan Anda untuk menggunakan sistem injeksi dependensi Angular untuk mengakses konstanta 'CONFIG' dalam modul yang membutuhkannya, tetapi Anda tidak berisiko mengambil risiko modul lain yang tidak. Misalnya, jika Anda menggunakan variabel global 'config', ada kemungkinan kode pihak ketiga lainnya mungkin juga mencari variabel yang sama.
JBCP
1
Saya seorang pemula sudut, berikut adalah beberapa catatan tentang bagaimana saya mendapatkan dependensi modul konfigurasi diselesaikan di aplikasi saya: gist.github.com/dsulli99/0be3e80db9b21ce7b989 ref: tutorials.jenkov.com/angularjs/… Terima kasih atas solusi ini.
dps
7
Disebutkan dalam komentar di salah satu solusi bootstrap manual lain di bawah ini, tetapi sebagai pemula yang tidak melihat, dapatkah saya tunjukkan bahwa Anda perlu menghapus perintah ng-app Anda dalam kode html agar dapat berfungsi dengan baik - itu mengganti bootstrap otomatis (melalui ng-app) dengan metode manual ini. Jika Anda tidak mengeluarkan aplikasi-ng, aplikasi sebenarnya dapat bekerja tetapi Anda akan melihat berbagai kesalahan penyedia yang tidak dikenal di konsol.
IrishDubGuy
49

Saya menggunakan pendekatan yang mirip dengan yang dijelaskan oleh @XMLilley tetapi ingin memiliki kemampuan untuk menggunakan layanan AngularJS suka $httpmemuat konfigurasi dan melakukan inisialisasi lebih lanjut tanpa menggunakan API tingkat rendah atau jQuery.

Menggunakan resolverute juga bukan pilihan karena saya membutuhkan nilai yang tersedia sebagai konstanta ketika aplikasi saya dimulai, bahkan dalam module.config()blok.

Saya membuat aplikasi AngularJS kecil yang memuat konfigurasi, menetapkan mereka sebagai konstanta pada aplikasi aktual dan bootstraps-nya.

// 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']);
});

Lihat dalam aksi ( $timeoutalih-alih menggunakan $http) di sini: http://plnkr.co/edit/FYznxP3xe8dxzwxs37hi?p=preview

MEMPERBARUI

Saya akan merekomendasikan untuk menggunakan pendekatan yang dijelaskan di bawah ini oleh Martin Atkins dan JBCP.

PEMBARUAN 2

Karena saya membutuhkannya di beberapa proyek, saya baru saja merilis modul bower yang menangani ini: https://github.com/philippd/angular-deferred-bootstrap

Contoh yang memuat data dari back-end dan menetapkan konstanta yang disebut APP_CONFIG pada modul AngularJS:

deferredBootstrapper.bootstrap({
  element: document.body,
  module: 'MyApp',
  resolve: {
    APP_CONFIG: function ($http) {
      return $http.get('/api/demo-config');
    }
  }
});
philippd
sumber
11
deferredBootstrapper adalah cara untuk pergi
fatlinesofcode
44

Kasing "manual bootstrap" dapat memperoleh akses ke layanan Angular dengan secara manual membuat injektor sebelum bootstrap. Injektor awal ini akan berdiri sendiri (tidak melekat pada elemen apa pun) dan hanya menyertakan sebagian dari modul yang dimuat. Jika yang Anda butuhkan adalah layanan inti Angular, itu cukup untuk memuat saja ng, seperti ini:

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']);
            }
        );
    }
);

Anda dapat, misalnya, menggunakan module.constantmekanisme untuk membuat data tersedia untuk aplikasi Anda:

myApp.constant('myAppConfig', data);

Ini myAppConfigsekarang dapat disuntikkan sama seperti layanan lain, dan khususnya itu tersedia selama tahap konfigurasi:

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

atau, untuk aplikasi yang lebih kecil, Anda bisa menyuntikkan konfigurasi global langsung ke layanan Anda, dengan mengorbankan penyebaran pengetahuan tentang format konfigurasi di seluruh aplikasi.

Tentu saja, karena operasi async di sini akan memblokir bootstrap aplikasi, dan dengan demikian memblokir kompilasi / penautan templat, sebaiknya gunakan ng-cloakarahan untuk mencegah agar templat yang tidak diuraikan muncul selama pekerjaan. Anda juga dapat memberikan semacam indikasi memuat di DOM, dengan menyediakan beberapa HTML yang hanya ditampilkan hingga AngularJS diinisialisasi:

<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>

Saya membuat contoh yang lengkap dan berfungsi dari pendekatan ini pada Plunker, memuat konfigurasi dari file JSON statis sebagai contoh.

Martin Atkins
sumber
Saya tidak berpikir Anda perlu menunda $ http.get () sampai setelah dokumen siap.
JBCP
@ JBCP ya, Anda benar bahwa itu berfungsi sama baiknya jika Anda menukar acara sehingga kami tidak menunggu dokumen siap hingga setelah respons HTTP dikembalikan, dengan keuntungan kemungkinan dapat memulai HTTP. meminta lebih cepat. Hanya panggilan bootstrap yang perlu menunggu sampai DOM siap.
Martin Atkins
2
Saya membuat modul bower
philippd
@ MartinAtkins, saya baru saja menemukan bahwa pendekatan hebat Anda tidak bekerja dengan Angular v1.1 +. Sepertinya versi awal Angular tidak mengerti "lalu" sampai aplikasi di-bootstrap. Untuk melihatnya di Plunk Anda ganti URL Angular dengan code.angularjs.org/1.1.5/angular.min.js
vkelman
16

Saya punya masalah yang sama: Saya suka resolveobjeknya, tapi itu hanya berfungsi untuk konten ng-view. Bagaimana jika Anda memiliki pengontrol (untuk nav tingkat atas, katakanlah) yang ada di luar ng-view dan yang perlu diinisialisasi dengan data sebelum perutean bahkan mulai terjadi? Bagaimana kita menghindari mucking di sisi server hanya untuk membuatnya bekerja?

Gunakan bootstrap manual dan konstanta sudut . XHR yang naif memberi Anda data Anda, dan Anda bootstrap secara bersudut dalam panggilan baliknya, yang berkaitan dengan masalah async Anda. Dalam contoh di bawah ini, Anda bahkan tidak perlu membuat variabel global. Data yang dikembalikan hanya ada dalam lingkup sudut sebagai injeksi, dan bahkan tidak ada di dalam pengontrol, layanan, dll. Kecuali Anda menyuntikkannya. (Seperti halnya Anda akan menyuntikkan output resolveobjek Anda ke controller untuk tampilan yang dirutekan.) Jika Anda lebih memilih untuk kemudian berinteraksi dengan data itu sebagai layanan, Anda dapat membuat layanan, menyuntikkan data, dan tidak ada yang akan lebih bijaksana .

Contoh:

//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();
})

Sekarang, NavDatakonstanta Anda ada. Teruskan dan menyuntikkannya ke pengontrol atau layanan:

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

Tentu saja, menggunakan objek XHR telanjang menghapus sejumlah kebaikan yang akan $httpatau JQuery rawat untuk Anda, tetapi contoh ini berfungsi tanpa ketergantungan khusus, setidaknya untuk yang sederhana get. Jika Anda ingin sedikit lebih banyak kekuatan untuk permintaan Anda, muat perpustakaan eksternal untuk membantu Anda. Tapi saya tidak berpikir itu mungkin untuk mengakses alat sudut $httpatau lainnya dalam konteks ini.

(SO terkait posting )

XML
sumber
8

Yang dapat Anda lakukan adalah di .config Anda untuk aplikasi ini adalah membuat objek tekad untuk rute dan dalam fungsi lulus dalam $ q (objek janji) dan nama layanan yang Anda andalkan, dan selesaikan janji di fungsi callback untuk $ http dalam layanan seperti:

CONFIG ROUTE

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;
          }
      })
}

Angular tidak akan merender template atau membuat controller tersedia sampai defer.resolve () dipanggil. Kami dapat melakukannya dalam layanan kami:

LAYANAN

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;
});

Sekarang MyService memiliki data yang ditetapkan untuk properti datanya, dan janji dalam objek resolusinya telah diselesaikan, pengontrol kami untuk rute tersebut menjadi nyata, dan kami dapat menetapkan data dari layanan ke objek pengontrol kami.

CONTROLLER

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

Sekarang semua pengikatan kami dalam lingkup controller akan dapat menggunakan data yang berasal dari MyService.

dewd
sumber
Saya akan mencoba ini ketika saya memiliki lebih banyak waktu. Ini mirip dengan apa yang orang lain coba lakukan di ngModules.
testing123
1
Saya suka pendekatan ini dan saya sudah menggunakannya sebelumnya, tetapi saya saat ini sedang mencoba mencari cara untuk melakukan ini dengan cara yang bersih ketika saya memiliki beberapa rute, yang masing-masing mungkin atau mungkin tidak tergantung pada data yang diambil sebelumnya. Adakah pemikiran tentang itu?
ivarni
btw, saya condong ke arah masing-masing layanan yang memerlukan data prefetch membuat permintaan ketika itu diinisialisasi dan mengembalikan janji dan kemudian mengatur menyelesaikan-objek dengan layanan yang diperlukan oleh rute yang berbeda. Saya hanya berharap ada cara yang kurang bertele-tele.
ivarni
1
@dewd Itulah yang saya tuju, tetapi saya lebih suka jika ada cara untuk mengatakan "ambil semua barang ini terlebih dahulu tanpa memandang rute mana yang dimuat" tanpa harus mengulangi blok-tekad saya. Mereka semua memiliki sesuatu yang mereka andalkan. Tapi ini bukan masalah besar, hanya akan terasa lebih KERING :)
ivarni
2
ini adalah rute yang akhirnya saya ambil kecuali saya harus membuat resolveobjek dengan properti menjadi fungsinya. jadi akhirnya menjadiresolve:{ dataFetch: function(){ // call function here } }
aron.duby
5

Jadi saya menemukan solusinya. Saya membuat layanan angularJS, kami akan menyebutnya MyDataRepository dan saya membuat modul untuk itu. Saya kemudian menyajikan file javascript ini dari pengontrol sisi server saya:

HTML:

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

Sisi server:

@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);
}

Saya kemudian dapat menyuntikkan MyDataRepository di mana pun saya membutuhkannya:

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

Ini bekerja dengan baik untuk saya, tetapi saya terbuka untuk umpan balik jika ada yang punya. }

testing123
sumber
Saya suka pendekatan modular Anda. Saya telah menemukan bahwa $ routeScope tersedia untuk layanan meminta data dan Anda dapat menetapkan data untuk itu dalam $ http.success callback. Namun, menggunakan $ routeScope untuk item non-global menciptakan bau dan data harus benar-benar ditugaskan ke lingkup $ controller. Sayangnya, saya pikir pendekatan Anda, meskipun inovatif, tidak ideal (hormat untuk menemukan sesuatu yang cocok untuk Anda). Saya hanya yakin harus ada jawaban hanya sisi klien yang entah bagaimana menunggu data dan memungkinkan penugasan untuk lingkup. Pencarian berlanjut!
dewd
Dalam hal ini berguna bagi seseorang, saya baru-baru ini melihat beberapa pendekatan berbeda melihat modul yang telah ditulis orang lain dan ditambahkan ke situs web ngModules. Ketika saya mendapatkan lebih banyak waktu saya harus mulai menggunakan salah satu dari itu, atau mencari tahu apa yang mereka lakukan dan menambahkannya ke barang-barang saya.
testing123
2

Selain itu, Anda dapat menggunakan teknik berikut untuk menyediakan layanan Anda secara global, sebelum pengendali yang sebenarnya dijalankan: https://stackoverflow.com/a/27050497/1056679 . runMisalnya , atasi data Anda secara global dan berikan ke layanan Anda di blok misalnya.

Slava Fomin II
sumber
1

Anda dapat menggunakan JSONPuntuk memuat data layanan secara tidak sinkron. Permintaan JSONP akan dilakukan selama pemuatan halaman awal dan hasilnya akan tersedia sebelum aplikasi Anda dimulai. Dengan cara ini Anda tidak perlu mengasapi perutean Anda dengan resolusi berlebihan.

Anda html akan terlihat seperti ini:

<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>
hegemon
sumber
-1

Cara termudah untuk mengambil inisialisasi direktori use ng-init.

Cukup masukkan lingkup div ng-init di mana Anda ingin mengambil data 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;
    });
  };

CATATAN: Anda dapat menggunakan metodologi ini jika Anda tidak memiliki kode yang sama lebih dari satu tempat.

Roni
sumber
Tidak disarankan untuk menggunakan ngInit sesuai dengan dokumen: docs.angularjs.org/api/ng/directive/ngInit
fodma1