1

Sorry for my english if it's very bad, i'm from Russia. I would want ask you. Help me please guys. I have the service in angular 4 and how can i manage it in many components?

This is my service:

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

@Injectable()
export class AuthService {
    status: boolean = false;
    userAuth: EventEmitter<boolean> = new EventEmitter();
    auth() {
      this.status = true;
      this.userAuth.emit(this.getAuth());
    }
    logout() {
      this.status = false;
      this.userAuth.emit(this.getAuth())
    }
    getAuth() {
      return this.status;
    }
}

This is my first component. I have already subscribed to service in ngOnInit

import {Component, OnInit} from '@angular/core';
import {ApiService} from "../../service/api/api.service";
import {BlockUI, NgBlockUI} from 'ng-block-ui'
import {AuthService} from "../../service/auth/auth.service";

@Component({
    selector: 'app-header',
    templateUrl: './header.component.html',
    styleUrls: ['./header.component.less'],
    providers: [ApiService, AuthService]
})
export class HeaderComponent implements OnInit {
    isLogin: boolean = false;
    @BlockUI() blockUI: NgBlockUI;
    constructor(private as: ApiService, public authService: AuthService) {
      this.blockUI.start();
      this.as.isLogin().then((res) => {
        if (res.hasError()) return false;
        if (res.getResponse().login) this.authService.auth();
        if (!res.getResponse().login) this.authService.logout();
        // this.isLogin = this.authService.getAuth();
        this.blockUI.stop();
      });
    }
    ngOnInit() {
      this.authService.userAuth.subscribe((status) => {
        this.isLogin = status;
        console.log('status', status);
        console.log('this.isLogin', this.isLogin);
      })
    }
    logout() {
      this.as.logout().then((res) => {
        if (res.hasError()) return false;
        this.authService.logout();
        // this.isLogin = this.authService.getAuth();
      });
    }
}

But if call the service in another component it'll call new service.

import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from "@angular/forms"
import {ApiService} from "../../service/api/api.service";
import {AuthService} from "../../service/auth/auth.service";

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.less'],
  providers: [ApiService, AuthService]
})
export class LoginComponent {
  formLogin: FormGroup;

  constructor(private fb: FormBuilder, private as: ApiService, public authService: AuthService) {
    this.formLogin = fb.group({
      email: [null, Validators.compose([Validators.required, Validators.pattern(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)])],
      password: [null, Validators.compose([Validators.required, Validators.minLength(6)])]
    });
  }

  auth(form) {
    this.as.authUser(form).then(res => {
      if (res.hasError()) return false;
      this.formLogin.reset();
      this.authService.auth();
    });
  }
}
tetra master
  • 537
  • 8
  • 13

2 Answers2

1

For each component you're receiving a new instance of AuthService because you provided the AuthService class in both components providers.

Angular2 Dependency Injection (DI) works more or less in the following way:

  • every component has its injector and its providers
  • when you ask DI to provide you an instance of something it checks in its providers and, if it finds the "recipe" there, it creates an instance, puts it in its injector and provides it as requested
  • if it doesn't find the "recipe" in its providers and the instance in its injector, the same request is lifted up to its father that in turn will check in its providers for a "recipe" or in its injector for an existing instance
  • when, going up in this hierarchical chain (up to the main module), its finds a provider for the requested token, the instance will be created and returned as requested
  • from that point, all the children of the component that have the injector with the request instance, will receive that instance as singleton.

So, going back to your specific issue, you're receiving two diffent instances of AuthService because both components contain its "recipe", so both of them create an instance, save it in their injector and return it when requested by the DI.

To solve your problem you can:

  • remove from each component's decorator metadata the provider for AuthService
  • add AuthService to the providers in the module decorator metadata.

__

@Component({
    selector: 'app-header',
    templateUrl: './header.component.html',
    styleUrls: ['./header.component.less'],
    providers: [ApiService]
})
export class HeaderComponent implements OnInit { /* ... */ }

__

@Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.less'],
    providers: [ApiService]
})
export class LoginComponent { /* ... */ }

And in the main module declaration

@NgModule({
    imports: [ /* ... */ ],
    declarations: [ /* ... */ ],
    providers: [AuthService, OtherServices],
})
Lorenzo Zottar
  • 426
  • 4
  • 10
0

You need to add it into your main module as angular creates singleton object of service, if you provide service in component level then service instance would be only specific to your particular component however you can not share data of service among the components. Hence you need to provide it in main module to share among the components.

Remove service providers from @Component and then just inject service into component's constructor

providers: [AuthService],

Your ng module should be like:

@NgModule({
      declarations: [
        AppComponent,
        LoginComponent,
        HeaderComponent,
     ],
      imports: [
        BrowserModule,
        RoutingModule
      ],
      providers: [AuthService],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
Rohan Fating
  • 2,135
  • 15
  • 24