2

We are preparing for upgrading our AngularJS app and refactoring for that. Currently we are running into an architectural issue:

Our app currently loads JSON through a jQuery AJAX call, this sets up all of the data and then bootstraps the app.

We need to move the AJAX call to Angular however, so that we can bootstrap the app without waiting for the AJAX to return (which is necessary for the upgrade)

$.get('/ajax/init').done(function (initData) {
  walletApp.run([
    'SomeService', function (someService) {
      // ...
    },
  ]);

  walletApp.config([
    'SomeProvider', function (someProvider) {
      // ...
    },
  ]);

  walletApp
    .factory('navInfo', function () {
      return initData.navInfo;
    })
    .factory('userInfo', function () {
      return initData.userInfo;
    });

  // ETC

  // Below is the important line
  angular.bootstrap(document, ['walletApp']);
});

I've been trying something along the lines of the below, where the initService gets the JSON feed and then assigns all of the data

angular.module('walletApp')
  .run([
    'InitService', function (initService) {
      initService.get();
    },
  ]);

angular.bootstrap(document, ['walletApp']);

But this results in a bunch of issues.

How do we properly load our AngularJS app, that requires data from AJAX to operate?

amphetamachine
  • 27,620
  • 12
  • 60
  • 72
Richard
  • 4,341
  • 5
  • 35
  • 55
  • Are you using `$http` and making the request ? If my understanding is correct then you want to load `JSON` data before loading the site . Please confirm – Shashank Vivek Feb 22 '19 at 12:55
  • Hi @ShashankVivek, am using `this.$http.get(url, {params: params})`. Yes the AJAX data is necessary for setting up the factories and other data. – Richard Feb 22 '19 at 12:59
  • check my answer , is this what you are looking for ? or can you make load the site and then setup the data while showing spinner till the call is complete? Let me know your feedback so that I can provide better solution – Shashank Vivek Feb 22 '19 at 13:34
  • A spinner would be fine while the AJAX loads, as long as we can call `angular.bootstrap` without depending on an AJAX call to complete. – Richard Feb 22 '19 at 13:45

1 Answers1

2

Ok, as per my understanding, You need json data before anything else of the UI loads (since it's a data which is required before the site even loads itself).

So, you can't make http on config phase and if you call in run phase, you have to wait till the main http call is made(Lets call it /site_data/).

  1. Don't use ng-app in index.html

  2. In app.js file

    (function() {
    
    var initInjector = angular.injector(['ng']);
    var $http = initInjector.get('$http');
    $http.get('/site_data/',{headers: {'Cache-Control' : 'no-cache'}}).then(
        function (response) {
            angular.module('walletApp.info', []).constant('SITE_CONF_DATA', response.data);
    
            angular.element(document).ready(function() {
                angular.bootstrap(document, ['walletApp']); //<--  manual bootstrapping of `ng-app`
            });
        }
      );
    })();
    
    var app = angular.module('walletApp',['walletApp.info']);
    app.config(function(SITE_CONF_DATA){
       // Bingo, you have the data
    })
    
    app.run().....
    
    app.controller...
    
    app.factory.....
    

This approach has a drawback that your site will be loaded once the http call is resolved.

Update

As per the comments, you are trying to build a hybrid application, so take a look at this demo.

  ngOnInit() {
    // Ensure AngularJS is only bootstrapped once.
    if (!angularJsBootstrapped) {
      this.http.get('https://jsonplaceholder.typicode.com/todos/1').delay(5000).subscribe(res => {
        angular.module('data',[]).constant('DATA',res);
        this.upgrade.bootstrap(document.body, [module.name]);
        setUpLocationSync(this.upgrade);
        angularJsBootstrapped = true;
      })
    }
  }

I have created a constant by creating a module after http is resolved and then I manually bootstrapped angularJS module.

angular.module('data',[]).constant('DATA',res);

Something like this might be helpful for the situation that you are describing.

Shashank Vivek
  • 16,888
  • 8
  • 62
  • 104
  • Thanks! However we can't use this solution as `angular.bootstrap` is called inside the callback of the AJAX request. We are busy with an Angular upgrade to version `6` and the bootstrapping of the app needs to happen from the Angular 6 code. So it doesn't know if the AJAX has completed. This solution is basically the same as I already have, but using AngularJS instead of jQuery for loading the data. – Richard Feb 22 '19 at 13:43
  • you are planning to call `angularjs` code from `angular 6` code ? – Shashank Vivek Feb 22 '19 at 13:44
  • https://v6.angular.io/guide/upgrade#bootstrapping-hybrid-applications - "this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });". When upgrading through a hybrid app, AngularJS gets bootstrapped through Angular – Richard Feb 22 '19 at 13:46
  • @Richard :Thanks for this awesome question. I have comeup with a solution and I have provided it as a demo . Let me know if it can an answer for you now. :) – Shashank Vivek Feb 23 '19 at 03:28
  • @Richard: did you find any solution ? – Shashank Vivek Apr 01 '19 at 08:22
  • Not yet, we are currently looking at other solutions here, we will probably be injecting the JSON directly into the HTML, so we don't need to fetch it on page load. Thanks for following up! – Richard Apr 01 '19 at 08:29