0

I would like to make a web API call as soon as my app starts. This Http call should return an array of Json objects.

I want to create HTML elements (in my root app) depending on how many elements were returned and then access and display that data in different (child->child->child) components without grinding it down to all those childs from the root app.

I guess I have to create a service class.

Questions

  1. Is a service instantiated as soon as the app is started or only when the first component is getting created that uses that service?
  2. Can I use a promise to achieve my desired behavior or do I have to use observable (BehaviorSubject)?
  3. According to 2. Is it possible to start a web API call (as soon as app starts) and then check from other indepentend components if the data already exists in my service and use it?
Florian Leitgeb
  • 15,657
  • 6
  • 31
  • 40
  • 1
    Personally I used `ngOnInit() { this.getNames() }` to return a list of users and then `
    • *ngFor="let name of names"
    ` to dynamically create a list element for each name returned. I'm not sure if that is of use to you directly but maybe it will be.
    – Christopher Lake Jul 14 '17 at 11:34
  • The problem with this approach is, that I have nested components in (your example given) the `li` elements and I dont want to grind the data like `name` all the way through my container and other components until I reach a component where I need it – Florian Leitgeb Jul 14 '17 at 12:32
  • 1
    check [this answer](https://stackoverflow.com/a/45063521/2545680) – Max Koretskyi Jul 14 '17 at 13:31

1 Answers1

0

You can use APP_INITIALIZER to call the HTTP method on startup, like described in this question.

If you go this route - if you use promise, the app won't load until the JSON is downloaded, if you use observable, it will start downloading on startup and continue rendering everything else.

If you store the returned values in a field of the service you can access them from everywhere.

Some code: app.module.ts

import { NgModule, APP_INITIALIZER } from '@angular/core';
import { Http, HttpModule, JsonpModule } from '@angular/http';
import { UserService } from '../services/user.service';

<...>
@NgModule({
  imports: [
    BrowserModule,
    HttpModule,
    FormsModule,
    JsonpModule,
    routing
  ],
  declarations: [
    AppComponent,
    <...>
  ],
  providers: [
    <...>
    UserService,
    {provide: APP_INITIALIZER,
      useFactory: (userServ: UserService) => () => userServ.getUser(),
      deps: [UserService, Http],
      multi: true
    }
  ],
  bootstrap: [AppComponent]

user.service.ts

@Injectable()
export class UserService {

    public user: User;
    constructor(private http: Http) { }

    getUser(): Promise<User> {
        console.log('get user called');
        var promise = this.http.get('/auth/getuser', { headers: getHeaders() })
            .map(extractData)
            .toPromise();
        promise.then(user => {
            this.user = user;
            console.log(this.user);
        });
        return promise;
    }
}
LLL
  • 3,566
  • 2
  • 25
  • 44
  • 1. I have read that the `APP_INITIALIZER` is still experimental and this is used in an app for our customer. 2. How do I know when the field in the service has my desired data from the web call? Because the app will defenitely render faster than the web call returns my data. – Florian Leitgeb Jul 14 '17 at 12:35
  • 1. It's not experimental anymore https://angular.io/api/core/APP_INITIALIZER 2. try a simple ngIf in the template or if that won't work or if you dont want to output from service directly to template, make an observable and broadcast that the data was loaded like here https://stackoverflow.com/documentation/angular2/7400/component-interactions/30136/bidirectional-parent-child-interaction-through-a-service#t=201707151320414474915 – LLL Jul 15 '17 at 13:21