37

I tried to inject AccountService in the LoginService but it won't ,the accountService is undefined but in the other hand the authServiceProvider is defined .

Contrarily it injected perfectly in footerComponent.

So why the AccountService is injected perfectly in FooterComponent and it bugs in the LoginService.

I do not know where the problem came from .

import { Injectable } from '@angular/core';
import { AccountService } from 'app/core/auth/account.service';
import { AuthServerProvider } from 'app/core/auth/auth-jwt.service';
@Injectable({ providedIn: 'root' })
export class LoginService {
    constructor(public accountService: AccountService, private authServerProvider: AuthServerProvider) {
        console.log(this.accountService); //  is undefined 
        console.log(this.authServerProvider); // is defined
}

This is the AuthentificationService

@Injectable({ providedIn: 'root' })
export class AuthServerProvider {
    constructor(private http: HttpClient, private $localStorage: LocalStorageService, private $sessionStorage: SessionStorageService) {}

This is the AccountService

@Injectable({ providedIn: 'root' })
export class AccountService {
    private userIdentity: any;
    private authenticated = false;
    private authenticationState = new Subject<any>();
    constructor(private languageService: JhiLanguageService, private sessionStorage: SessionStorageService, private http: HttpClient) {}

I tried to use AccountService in other component and it injected perfectly

import { Component } from '@angular/core';
import { AccountService } from 'app/core';
@Component({
    selector: 'jhi-footer',
    templateUrl: './footer.component.html',
    styleUrls: ['./footer.component.scss']
})
export class FooterComponent {

    constructor( private accountService: AccountService) {
        console.log(this.accountService); // It is defined

    }
}

this is the app.module.ts

import './vendor.ts';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap';
import { Ng2Webstorage } from 'ngx-webstorage';
import { NgJhipsterModule } from 'ng-jhipster';
import { AuthInterceptor } from './blocks/interceptor/auth.interceptor';
import { AuthExpiredInterceptor } from './blocks/interceptor/auth-expired.interceptor';
import { ErrorHandlerInterceptor } from './blocks/interceptor/errorhandler.interceptor';
import { NotificationInterceptor } from './blocks/interceptor/notification.interceptor';
import { SharedModule } from 'app/shared';
import { CoreModule } from 'app/core';
import { AppRoutingModule } from './app-routing.module';
import { HomeModule } from './home/home.module';
import { AccountModule } from './account/account.module';
import { EntityModule } from './entities/entity.module';
import * as moment from 'moment';
// jhipster-needle-angular-add-module-import JHipster will add new module here
import { JhiMainComponent, NavbarComponent, FooterComponent, PageRibbonComponent, ActiveMenuDirective, ErrorComponent } from './layouts';
@NgModule({
    imports: [
        BrowserModule,
        Ng2Webstorage.forRoot({ prefix: 'jhi', separator: '-' }),
        NgJhipsterModule.forRoot({
            // set below to true to make alerts look like toast
            alertAsToast: false,
            alertTimeout: 5000,
            i18nEnabled: true,
            defaultI18nLang: 'en'
        }),
        SharedModule.forRoot(),
        CoreModule,
        HomeModule,
        AccountModule,
        // jhipster-needle-angular-add-module JHipster will add new module here
        EntityModule,
        AppRoutingModule
    ],
    declarations: [JhiMainComponent, NavbarComponent, ErrorComponent, PageRibbonComponent, ActiveMenuDirective, FooterComponent],
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: AuthInterceptor,
            multi: true
        },
        {
            provide: HTTP_INTERCEPTORS,
            useClass: AuthExpiredInterceptor,
            multi: true
        },
        {
            provide: HTTP_INTERCEPTORS,
            useClass: ErrorHandlerInterceptor,
            multi: true
        },
        {
            provide: HTTP_INTERCEPTORS,
            useClass: NotificationInterceptor,
            multi: true
        }
    ],
    bootstrap: [JhiMainComponent]
})
export class AppModule {
    constructor(private dpConfig: NgbDatepickerConfig) {
        this.dpConfig.minDate = { year: moment().year() - 100, month: 1, day: 1 };
    }
}

and this is the core.module .

import { NgModule, LOCALE_ID } from '@angular/core';
import { DatePipe, registerLocaleData } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { Title } from '@angular/platform-browser';
import locale from '@angular/common/locales/en';
@NgModule({
    imports: [HttpClientModule],
    exports: [],
    declarations: [],
    providers: [
        Title,
        {
            provide: LOCALE_ID,
            useValue: 'en'
        },
        DatePipe
    ]
})
export class CoreModule {
    constructor() {
        registerLocaleData(locale);
    }
}

Thanks in advance for your help.

Ridae HAMDANI
  • 686
  • 2
  • 7
  • 17
  • 1
    can you please share your module definitions? – Derviş Kayımbaşıoğlu Mar 18 '19 at 21:32
  • Can you make sure both of your services are in the providers array in your app.module.ts file – O.MeeKoh Mar 18 '19 at 21:37
  • @DervişKayımbaşıoğlu I add the module definition – Ridae HAMDANI Mar 18 '19 at 21:45
  • 2
    @O.MeeKoh no they aren't because of @Injectable({ providedIn: 'root' }) – Ridae HAMDANI Mar 18 '19 at 21:46
  • 1
    Im not 100% sure, but you may be missing something in order to inject a service into another service when using the providedIn:root property. Try simply simply removing the @Injectable() from your AccountService service, and but specify it into the app.module.ts providers array. See if this works – O.MeeKoh Mar 18 '19 at 21:54
  • 1
    @O.MeeKoh thanks for your help. It works when I add it in the app.module but I dont know why it does not with @Injectable({ providedIn: 'root' }) even both of theme do the same job . – Ridae HAMDANI Mar 18 '19 at 22:30
  • Does this answer your question? [Passing function to child component, wrong context of 'this'](https://stackoverflow.com/questions/45690530/passing-function-to-child-component-wrong-context-of-this) – Liam May 13 '20 at 13:06
  • Resolved this issue just by adding HttpClientModule in imports section in AppModule. – Subbu Sep 23 '20 at 11:57

5 Answers5

32

The same thing happened to me, the solution was the one mentioned by the user span

-> Passing arrow function instead of regular function in the callback. Arrow functions don't have its own this.

Difference between regular functions and arrow functions here

Liam
  • 27,717
  • 28
  • 128
  • 190
Carherpi
  • 701
  • 7
  • 6
  • This is [covered in more details here](https://stackoverflow.com/questions/45690530/angular-passing-function-to-child-component-wrong-context-of-this) – Liam May 13 '20 at 13:04
  • 3
    I can't see the relation between the code in the question, and arrow functions. The OP only talks about `constructor`s, he nevers calls `new LoginService(...)` so why the hell would there be a context issue ? – Random Jul 30 '21 at 14:51
26

You should always provide your service in the root injector unless there is a case where you want the service to be available only if the consumer imports a particular @NgModule.

try to add your service you want to inject in providers : [ ] in your core.module

import { NgModule, LOCALE_ID } from '@angular/core';
import { DatePipe, registerLocaleData } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { Title } from '@angular/platform-browser';
import locale from '@angular/common/locales/en';
@NgModule({
    imports: [HttpClientModule],
    exports: [],
    declarations: [],
    providers: [
        AccountService,
        Title,
        {
            provide: LOCALE_ID,
            useValue: 'en'
        },
        DatePipe
    ]
})
export class CoreModule {
    constructor() {
        registerLocaleData(locale);
    }
}

and in your AccountService replace @Injectable({ providedIn: 'root' }) with @Injectable()

@Injectable()
export class AccountService {
    private userIdentity: any;
    private authenticated = false;
    private authenticationState = new Subject<any>();
    constructor(private languageService: JhiLanguageService, private sessionStorage: SessionStorageService, private http: HttpClient) {}
ZINE Mahmoud
  • 1,272
  • 1
  • 17
  • 32
  • 6
    Thanks bro It works but I do not know why it works in this case , I think in angular 7 if we used provideIn property there is no need to add the service into providers . – Ridae HAMDANI Mar 18 '19 at 22:47
  • Would love an elaboration on why and how this works. A link to docs would be nice as well. – span Jul 22 '19 at 20:22
  • 1
    @span here is a [link](https://angular.io/guide/providers#providers) trying to explain you how does provider works – ZINE Mahmoud Jul 23 '19 at 14:22
  • 16
    Thanks for the link. I'd been all over it without resolving my issue. Until I remembered the old days of using var this = that etc... I was getting undefined since I was passing a normal function as a callback instead of an arrow function. They have different this scope. Hopefully someone stumbles over this :) – span Jul 23 '19 at 21:07
  • 10
    I think the point of the question is why doesn't it work with `@Injectable({ providedIn: 'root' })`. This answer mitigates the problem behind this question but basically goes against the Angular docs, that say that `Beginning with Angular 6.0, the preferred way to create a singleton service is to set providedIn to root on the service's @Injectable() decorator.` – RTYX Oct 16 '19 at 09:03
  • 1
    @RidaeHAMDANI, did you come to know, why it's not working with @Injectable({ providedIn: 'root' })? – Rahul Upadhyay Sep 14 '20 at 12:43
  • @rahul-upadhyay Unfortunately I did not – Ridae HAMDANI Sep 14 '20 at 13:23
0

HttpClientModule is required for HttpClient. Just import in AppModule.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
import { HttpClientModule } from '@angular/common/http';
import { MatTreeModule } from '@angular/material';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    CoreModule,
    MatTreeModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule //add this as fix, simple
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Subbu
  • 308
  • 2
  • 4
  • 12
0

I had a similar problem when by a mistake I used an interface instead of a class implementation in the injection inside of the problematic service.

Eugene P.
  • 1,517
  • 12
  • 16
0

If someone else is facing the issue to this day using functional guards, double check if you are importing

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

and not

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

This solved my issue, perhaps this fixes your issue.

ali
  • 1
  • 2