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

Global Javascript Var Я міг би надіслати свій JSON безпосередньо до глобальної змінної Javascript:

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

Це теж працюватиме, але тоді у мене є глобальна змінна javascript, яка погано пахне.

Це мої єдині варіанти? Чи один із цих варіантів кращий за інші? Я знаю, що це досить довге питання, але я хотів показати, що я намагався вивчити всі свої варіанти. Будь-які вказівки будуть дуже вдячні.


angular - завантажувальний асинхронно проходить через код, щоб витягнути дані з сервера $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 ініціалізується?
тестування123

2
Напевно, я б обіцяв обіцянки в MyOtherService - я оновив планкер ланцюжком та деякими коментарями - як це виглядає? plnkr.co/edit/Z7dWVNA9P44Q72sLiPjW?p=preview
joakimbl

3
Я спробував це, і все-таки зіткнувся з деякими проблемами, оскільки у мене є директиви та інші контролери (контролер, який я використовую з $ routeProvider, обробляє первинний, вторинний навігаційний матеріал ... тобто "MyOtherService"), на який потрібно почекати, поки "MyService 'вирішено. Я буду намагатися і оновлювати це з будь-яким успіхом у мене. Я просто хочу, щоб у кутку був гачок, куди я міг зачекати, коли дані повернуться, перш ніж ініціалізувати контролери та директиви. Ще раз дякую за вашу допомогу. Якби у мене був головний контролер, який обгортав усе, це працювало б.
тестування123

43
Тут питання - як ви призначите resolveвластивість контролеру, про який не йдеться $routeProvider. Наприклад, <div ng-controller="IndexCtrl"></div>. Тут контролер прямо згадується та не завантажується через маршрутизацію. У такому випадку, як би тоді затримати екземпляр контролера?
callmekatootie

19
Ummm, що робити, якщо ви не використовуєте маршрутизацію? Це майже так, як сказати, що ви не можете написати кутовий додаток з асинхронними даними, якщо не використовуєте маршрутизацію. Рекомендований спосіб отримати дані в додаток - це завантажувати їх асинхронно, але як тільки у вас є більше одного контролера і ви передаєте послуги, БУМ неможливо.
wired_in

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, коли вона стає доступною.

Повністю дочекавшись, поки документ буде готовий, а потім завантажимо додаток Angular.

Це незначне вдосконалення щодо рішення Мартіна, яке відклало отримання конфігурації до готовності документа. Наскільки мені відомо, немає причин затримувати виклик $ http для цього.

Тестування одиниць

Примітка. Я виявив, що це рішення не працює добре при тестуванні одиниць, коли код включений у ваш app.jsфайл. Причиною цього є те, що вищезазначений код запускається негайно при завантаженні файлу JS. Це означає, що тестова рамка (в моєму випадку Жасмін) не має шансів забезпечити макетну реалізацію $http.

Моїм рішенням, яким я не повністю задоволений, було переміщення цього коду до нашого index.htmlфайлу, тому тестова інфраструктура підрозділу Grunt / Karma / Jasmine не бачить цього.


1
Таке правило, як "не забруднюйте глобальну сферу дії", слід дотримуватися лише в тій мірі, в якій вони покращують наш код (менш складний, більш досяжний, більш безпечний тощо). Я не бачу, наскільки це рішення краще, ніж просто завантаження даних в єдину глобальну змінну. Що я пропускаю?
david004

4
Це дозволяє використовувати систему впорскування залежностей Angular для доступу до константи 'CONFIG' в модулях, які її потребують, але ви не ризикуєте клобувати інші модулі, які цього не роблять. Наприклад, якщо ви використовували глобальну змінну 'config', є ймовірність, що інший сторонній код також може шукати ту саму змінну.
JBCP

1
Я новичок у кутку , ось декілька зауважень щодо того, як я вирішив залежність модуля конфігурації у своєму додатку: gist.github.com/dsulli99/0be3e80db9b21ce7b989 ref: tutorials.jenkov.com/angularjs/… Дякую за це рішення.
дпс

7
Це згадується в коментарі в одному з інших ручних рішень для завантаження нижче, але як кутовий новачок, який цього не помітив, я можу лише зазначити, що вам потрібно видалити директиву ng-програми у своєму коді html, щоб це нормально працювало - це заміна автоматичної завантажувальної програми (через ng-додаток) цим ручним методом. Якщо ви не виймаєте ng-додаток, програма може насправді працювати, але на консолі ви побачите різні невідомі помилки постачальників.
IrishDubGuy

49

Я використовував подібний підхід до описаного в @XMLilley, але хотів мати можливість використовувати сервіси AngularJS, як $httpзавантажувати конфігурацію і робити подальшу ініціалізацію без використання API низького рівня або 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

ОНОВЛЕННЯ

Я рекомендував би використовувати підхід, описаний нижче Мартіном Аткінсом та JBCP.

ОНОВЛЕННЯ 2

Оскільки мені це було потрібно в декількох проектах, я щойно випустив модуль прив'язки, який займається цим: https://github.com/philippd/angular-deferred-bootstrap

Приклад, який завантажує дані з бек-енду і встановлює константу під назвою APP_CONFIG на модулі AngularJS:

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

11
deferredBootstrapper - це шлях
fatlinesofcode

44

Випадок "ручного завантаження" може отримати доступ до служб Angular, створивши інжектор перед завантаженням вручну. Цей початковий інжектор буде стояти окремо (не бути прикріпленим до будь-яких елементів) і міститиме лише підмножину завантажених модулів. Якщо все, що вам потрібно, це основні кутові послуги, достатньо просто завантажити 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);
    }
);

або, для меншої програми, ви можете просто ввести глобальну конфігурацію безпосередньо у вашу службу, за рахунок поширення знань про формат конфігурації у всій програмі.

Звичайно, оскільки операції з асинхронізацією тут заблокують завантажувальний додаток і тим самим заблокують компіляцію / посилання шаблону, розумно використовувати 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>

Я створив повний робочий приклад такого підходу на Plunker, завантажуючи конфігурацію зі статичного файлу JSON як приклад.


Я не думаю, що вам потрібно відкладати $ http.get (), поки документ не буде готовий.
JBCP

@JBCP так, ви маєте рацію, що це працює так само добре, якщо ви поміняєте місцями події, щоб ми не чекали, коли документ стане готовим до повернення відповіді HTTP, з перевагою можливо, що можна буде запустити HTTP запит швидше. Потрібно чекати лише виклику завантажувача, поки DOM не буде готовий.
Мартін Аткінс

2
Я створив модуль прив'язки
philippd

@MartinAtkins, я щойно виявив, що ваш чудовий підхід не працює з Angular v1.1 +. Схоже, ранні версії Angular просто не розуміють "тоді", поки додаток не завантажиться. Щоб побачити це у своєму Plunk, замініть кутову URL-адресу на code.angularjs.org/1.1.5/angular.min.js
vkelman

16

У мене була така ж проблема: я люблю resolveоб'єкт, але це працює лише для вмісту ng-view. Що робити, якщо у вас є контролери (для навигації верхнього рівня, скажімо так), які існують поза ng-view і які потрібно ініціалізувати з даними, перш ніж маршрутизація навіть почне відбуватися? Як ми можемо уникати витівки на стороні сервера просто для того, щоб це працювало?

Використовуйте ручну завантажувальну стрічку та кутову константу . Наївний XHR отримує ваші дані, і ви завантажуєте кут у зворотному дзвінку, який стосується ваших проблем з асинхронізацією. У наведеному нижче прикладі вам навіть не потрібно створювати глобальну змінну. Повернені дані існують лише в кутовій області як ін'єкційні, і навіть не є всередині контролерів, служб тощо, якщо ви не вводили їх. (Подібно до того , як ви б впорснути вихід вашого 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 
}]);

Звичайно, використання голого XHR-об’єкта позбавляє ряду приємностей, які $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, я схиляюся до того, щоб кожна служба, яка вимагає попередньо встановлених даних, зробила запит, коли він ініціалізований, і поверне обіцянку, а потім встановить об'єкти Resol-сервісу з необхідними службами різних маршрутів. Я просто хочу, щоб був менш дослівний спосіб.
ivarni

1
@dewd Це те, на що я мав на меті, але я б вважав за краще, якби був якийсь спосіб просто сказати «заздалегідь отримати весь цей матеріал, незалежно від того, який маршрут завантажений», не повторюючи своїх блоків вирішення. У всіх них є щось, від чого вони залежать. Але це не велика справа, було б просто відчути трохи більше
ДРУГО

2
це маршрут, який я в кінцевому підсумку взяв, за винятком того, що я повинен був створити resolveоб'єкт, властивість якого функціонує. так воно закінчилосяresolve:{ dataFetch: function(){ // call function here } }
aron.duby

5

Тому я знайшов рішення. Я створив службу angularJS, ми будемо називати його MyDataRepository, і я створив модуль для нього. Потім я надсилаю цей файл JavaScript від мого серверного контролера:

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

Для мене це спрацювало чудово, але я відкритий для будь-яких відгуків, якщо хтось має. }


Мені подобається ваш модульний підхід. Я виявив, що $ routeScope доступний для сервісу, що запитує дані, і ви можете призначити їм дані у зворотному дзвінку $ http.success. Однак використання $ routeScope для неглобальних елементів створює запах, і дані дійсно повинні бути призначені до області контролера $. На жаль, я думаю, що ваш підхід, хоча і інноваційний, не є ідеальним (повага, хоча знайти щось, що працює для вас). Я просто впевнений, що повинен відповідати лише клієнт, який якимось чином чекає на дані та дозволяє присвоїти обсяг. Пошук триває!
роса

У випадку, якщо комусь це корисно, я нещодавно побачив різні підходи, дивлячись на модулі, які інші люди написали та додали на веб-сайт ngModules. Коли я отримаю більше часу, мені доведеться або почати використовувати один із них, або зрозуміти, що вони зробили, і додати його до своїх речей.
тестування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

Найпростіший спосіб отримати будь-яку ініціалізацію використовувати каталог ng-init.

Просто поставте область ng-init div там, де ви хочете отримати дані 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: docs.angularjs.org/api/ng/directive/ngInit
fodma1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.