Nuno_147
Nuno_147

Reputation: 2913

Mandatory service initialization in AngularJS

I am new the AngularJS, and I am trying to do something which sounds a bit trivial but I am struggling to decide what is the best approch.

I have a service in AnuglarJS which handle all of my REST communication with my server.

To avoid url name changing between my client/server, I have created a REST API which is called get_apis and it responsible to return an array of all of my apis function with their freindly name such as :

{
    'get_user' :'/api/get_user',
    'delete_user' : '/api/delete_user'
}

The problem I am having is that all of my other services/controllers depends on this call, otherwise the APIS will not be available for any other rest operations until this call completes.

Assuming I am doing the get_apis rest operation on my API service constructor, still the rest operation is async, so I just cant make sure I have the api.

Any "right way" to do it ? maybe my approch of re-mapping my urls is wrong ?

Upvotes: 0

Views: 671

Answers (4)

gesellix
gesellix

Reputation: 3124

Additionally to the other answers you should know about manual AngularJS bootstrapping as described here: API reference / angular.bootstrap You can find a comparison of some possibilities including an example of angular.bootstrap here.

We used another approach with a dedicated initialization service to configure our app and forced our controllers to wait for other controllers or services to finish their initializing tasks. A very detailed description can be found at our blog, and some discussion has started at the AngularJS forum. The code is available as jsfiddle and would look like this inside your controller:

init('userCtrl', [apiResolutionService.getApiUrls()], function(result) {
    var apiUrls = result[0].data.apiUrls;
    var user = $http.get(apiUrls.get_user, ...);
});

Upvotes: 0

package
package

Reputation: 4801

There is no simple solution since your app needs to make async call before it is properly initialized.

There are several solutions.

  1. Inject required data into main template of the app. Let's say you have a template index.html, which is served by your backend and where all scripts are included. Your backend could include one more script with your api functions. When you think of it, your api in the production code will not change frequently, therefore issuing a call for api functions everytime app starts does not make sense. Instead, you maintain a static .json or .js file with your apis and include it in the html itself. Function names would be ready at app boot time.

  2. Make async call in .config or .run block of your app delaying all normal operations until api function list is fetched. This is maintenance nightmare because every single operation with api must first check a boolean flag or listen for event or depend on promise to be sure api function list is ready.

  3. Using angular routing mechanisms (I prefer ui-state module), define top-level/root/main route or state that is initialized on "/" location and add api function call as it's dependency in resolve list.

I'm not really sure if this is possible with generic routes, but with states you could do something like this:

.config(['$stateProvider'], function($stateProvider) {
   $stateProvider.state('main', {
      resolve: {
        apis: ['APIService', function(APIService) {
          return APIService.getApis();
        }]
      }
   }).state('someState', {
      parent: 'main',
      ...
   })
  ...
 })

All other states would depend on 'main' and none of them would be initialized before your api functions list is ready.

Upvotes: 1

kubuntu
kubuntu

Reputation: 2535

One way you can achieve this will be to wrap the codes of the components that need the service at start-up in a function (assuming they are in controllers). Then you inject $rootScope in the API service constructor you mentioned. The $rootScope retrieves the APIs on start-up and dispatches an initialize event, using $broadcast('eventName'), which other components (say controllers) can respond to, in their $on('eventName'), by calling their start-up functions.

Edit: Here is a Fiddle that demonstrates this if I understood the problem correctly.

Upvotes: 1

Joe Minichino
Joe Minichino

Reputation: 2773

I'm not sure I understand the problem fully, but if you're just trying to define urls for your REST calls in a central place so that they are available to all services i would do something like

angular.module('myApp', [])
  .constant('REST_API_URLS', (function () {
      return {
        'get_user' :'/api/get_user',
        'delete_user' : '/api/delete_user'
      };
    })()
  )
  .service('MyRESTService', function ($http, REST_API_URLS) {
    $http.get(REST_API_URLS.get_user)
    .success() // etc
  });

Upvotes: 0

Related Questions