9

I have two services. login.service.ts and environment-specific.service.ts.

In login.service.ts I need to initialize a Json object from environment-specific.service.ts which passes a couple of links.

The use case is how to make this working in the servcie without ngOnInit(){}, because ngOnInit() can't be used within a servcie as per Angular2 Lifecycle Hook.

Here you find the part I must initialize inside in login.service.ts - of course without ngOnInit() method:

...
import { EnvSpecific } from '../models/env-specific';
import { ActivatedRoute } from "@angular/router";

@Injectable()
export class LoginService {

   link1: string;
   link2: string;
   link3: string;

   constructor(private http: Http, private fbuilder:FormBuilder, private route: ActivatedRoute) { }

   ngOnInit(){
      this.route.data
         .subscribe((data: { envSpecific: EnvSpecific }) => {
            this.link1 = data.envSpecific.link1;
            this.link2 = data.envSpecific.link2;
            this.link3 = data.envSpecific.link3;
      });
   }
   ...
   ...
}

and I would like to pass the link(s) to the URL passed to different http.post API call. e.g:

...
var obsRequest = this.http.post( this.link1, serializedForm, this.options )
...

The Error is clear: link1 is undefined

Any suggestion or a hint please?

Andrei Matracaru
  • 3,511
  • 1
  • 25
  • 29
k.vincent
  • 3,743
  • 8
  • 37
  • 74
  • Why not in the constructor? – Robin Dijkhof Aug 10 '17 at 14:31
  • @Robin Dijkhof: I tried.. unfortunately didn't work. When I initialize it inside a component, it works fine and I access e.g. `link1` which means that the code if fine. Just inside a service it doesn't. – k.vincent Aug 10 '17 at 14:32
  • Did you try to set link1 to an object in the class member definition? Where you do `link1: string;`, change it to `link1: string = '...';`. Also, did you try moving the `this.route.subscribe` line into your constructor? That way it will be called when the service is instantiated. – Lansana Camara Aug 10 '17 at 14:39
  • @Lansana: I'am not sure if I understand what you exactly mean with the first hint. But regarding the second one, yes I did: `constructor(private http: Http, private fbuilder:FormBuilder, private route: ActivatedRoute) { this.route.data .subscribe((data: { envSpecific: EnvSpecific }) => { this.link1 = data.envSpecific.link1; this.link2 = data.envSpecific.link2; this.link3 = data.envSpecific.link3; }); } Error: `Cannot read property link1 of undefined` – k.vincent Aug 10 '17 at 14:45
  • Are you just trying to get a value from your environment file to use in your login service? Why don't you just import the environment variables instead of passing it in from the URL? – Lansana Camara Aug 10 '17 at 14:46
  • @Lansana: I already did this, and it wokrs fine. But I do have other use cases and requirements where I better use a suctomized env. file and load it when inizializing the app. – k.vincent Aug 10 '17 at 14:49
  • Can you explain your use case? It seems to me that this may be overcomplicated. – Lansana Camara Aug 10 '17 at 14:54
  • @Lansana: Sure. I want to deploy the App with a specific environment, so that I'll be able to do one build that is tested in dev, QA and then goes to production without rebuilding. – k.vincent Aug 10 '17 at 15:01
  • How are you updating the env variables? Can you not just update the env variables and import the same variable that will change based on the specific environment? – Lansana Camara Aug 10 '17 at 15:03
  • @Lansana: It's done via a json file saved as/in .ts file. By the way, this [Define global constants in Angular 2] (https://stackoverflow.com/questions/34986922/define-global-constants-in-angular-2) here is a kind of what you're suggesting... – k.vincent Aug 10 '17 at 15:10
  • This seems like an antipattern to me. Why not just use the native Angular 2 environment that is set up for you by default with Angular CLI? It has both development/production versions and you can set your values in there however you want, and just import it in your service. Based on dev/prod, the different env variables will be used. – Lansana Camara Aug 10 '17 at 15:13
  • @Lansana: I may agree with you! I'll give it more tries inside the costructor of the service... and if it causes more issues and and conflicts with the rest of the code, I'll move to Angular2 built-in Env/Prod once again. Helpful Hint! – k.vincent Aug 10 '17 at 15:22
  • Let me know if that works. Will add an answer. – Lansana Camara Aug 10 '17 at 15:25
  • @Lansana: Sure, I'll do. But which one? The answer regarding using costructor or using the built-in Env? You helped me with both ;-) – k.vincent Aug 10 '17 at 15:27
  • Added both of them! – Lansana Camara Aug 10 '17 at 15:28

2 Answers2

4

You could move your logic in the ngOnInit in your service to the service's constructor. But even then, the link1 property may not be set immediately, so you may want to provide a default value for it.

But this seems like an antipattern to me. You can just use the native Angular 2 environment that is set up for you by default with Angular CLI.

It has both development/production variants and you can set your values in there however you want, and just import it in your service. Based on the way you do ng build (if you pass -prod flag or not), the different env variables will be used.

Lansana Camara
  • 9,497
  • 11
  • 47
  • 87
  • 1
    I go for the option with Angular2 built-in Env. The one with service constructor doesn't give the expected result. – k.vincent Aug 10 '17 at 15:52
4

You can initialized your service at first by app initialization before using of the services.

That can be done with APP_INITIALIZER, see:

https://devblog.dymel.pl/2017/10/17/angular-preload/

Angular: How to correctly implement APP_INITIALIZER

Mark
  • 17,887
  • 13
  • 66
  • 93