Hongbo Miao
Hongbo Miao

Reputation: 49996

How to run a service when the app starts in Angular 2

I created a service SocketService, basically it initializes the socket to let the app listen on the port. This service also interacts with some components.

// socket.service.ts

export class SocketService {
    constructor() {
        // Initializes the socket
    }
    ...
}

I know the code in SocketService's constructor() only starts to run when a component use SocketService.

And usually the code in app.ts looks like this:

// app.ts

import {SocketService} from './socket.service';
...
class App {
    constructor () {}
}
bootstrap(App, [SocketService]);

However, I want this service run when the app starts. So I made a trick, just add private _socketService: SocketService in App's constructor(). Now the code looks like this:

// app.ts (new)

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {}
}
bootstrap(App, [SocketService]);

Now it works. The problem is sometimes the code in SocketService's constructor() runs, and sometimes not. So how should I do it correctly?

Upvotes: 135

Views: 115539

Answers (6)

Mo D Genesis
Mo D Genesis

Reputation: 6179

socket.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class SocketService {
  init() {
    console.log("socket service initialized");
  }
}

app.component.ts

import { Component } from '@angular/core';
import {SocketService} from './socket.service';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor(private _socketService: SocketService) {
    this._startupService.init();
  }
}

Upvotes: 1

K24
K24

Reputation: 1

in config.teml.json
{Domain:'your url'}

in app.module.ts

import * as mydata from '../assets/config.teml.json';
const data:any=(mydata as any).default;
let config: SocketIoConfig = { url: data.Domain, options: { } };

Upvotes: 0

GMK
GMK

Reputation: 2950

Stuart's answer points in the right direction, but it's not easy to find information on APP_INITIALIZER. The short version is you can use it to run initialization code before any of your other application code runs. I searched for a while and found explanations here and here, which I will summarize in case they disappear from the web.

APP_INITIALIZER is defined in angular/core. You include it in your app.module.ts like this.

import { APP_INITIALIZER } from '@angular/core';

APP_INITIALIZER is an OpaqueToken (or an InjectionToken since Angular 4) that references the ApplicationInitStatus service. ApplicationInitStatus is a multi provider. It supports multiple dependencies and you can use it in your providers list multiple times. It is used like this.

@NgModule({
  providers: [
    DictionaryService,
    {
      provide: APP_INITIALIZER,
      useFactory: (ds: DictionaryService) => () => return ds.load(),
      deps: [DictionaryService],
      multi: true
    }]
})
export class AppModule { }

This provider declaration tells the ApplicationInitStatus class to run the DictionaryService.load() method. load() returns a promise and ApplicationInitStatus blocks the app startup until the promise resolves. The load() function is defined like this.

load(): Promise<any> {
  return this.dataService.getDiscardReasons()
  .toPromise()
  .then(
    data => {
      this.dictionaries.set("DISCARD_REASONS",data);
    }
  )
}

Set up like that the dictionary gets loaded first and the other parts of the app can safely depend on it.

Edit: Be aware that this will increase the up-front load time for you app by however long the load() method takes. If you want to avoid that you could use a resolver on your route instead.

Upvotes: 174

Stuart Hallows
Stuart Hallows

Reputation: 8963

Also see APP_INITIALIZER, which is described as;

A function that will be executed when an application is initialized.

Upvotes: 11

Bhushan Gadekar
Bhushan Gadekar

Reputation: 13805

Try Creating service constructor & then call it in ngOnInit() of your component.

  • Service Module

 export class SocketService {
    constructor() { }
        getData() {
            //your code Logic
        }
}

  • Component

export class AppComponent {
    public record;  
    constructor(private SocketService: DataService){ }
    ngOnInit() {        
        this.SocketService.getData()
        .subscribe((data:any[]) => {
            this.record = data;
        });   
  }  
}       

Hope this Helps.

Upvotes: 0

SnareChops
SnareChops

Reputation: 13347

Move the logic in your SocketService constructor to a method instead and then call that in your main component's constructor or ngOnInit

SocketService

export class SocketService{
    init(){
        // Startup logic here
    }
}

App

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {
        _socketService.init();
    }
}
bootstrap(App, [SocketService]);

Upvotes: 62

Related Questions