Angular service is undefined when fetching backend data in its constructor












0















I have a SessionService which manages JWT token and stores user data. When my app is started I need to fetch user data from backend via http. It might be a bad idea, but since there is no ngOnInit() for services I do it in SessionService constructor:



@Injectable({
providedIn: 'root'
})
export class SessionService {
constructor(
private errHandler: ErrorHandlingService,
private backend: UsersService
) {
const initialToken = this.rawToken; // localStorage.getItem('jwt')
if (!initialToken || this.isTokenExpired(initialToken)) {
localStorage.removeItem('jwt');
return;
}
this.fetchUser();
}

private fetchUser() {
this.backend.getMe().subscribe(
user => this.user = user,
err => this.errHandler.handle(err)
);
}
/* ... */
}


I think this is pretty straightforward, UsersSevice::getMe() is just an abstraction for:



    getMe() {
return this.http.get<Api.V1.Me.Get.Response>('/api/v1/me');
}


The problem is that my HttpInterceptor that attaches JWT to the header of each http request, that it obtains via my SessionServicegets this service as undefined, so the TypeError is raised when accessing its rawRoken getter (can not read property rawToken of undefined)



@Injectable()
export class JwtInterceptor implements HttpInterceptor {

constructor(private session: SessionService) {}

intercept(req: HttpRequest<unknown>, next: HttpHandler) {
const rawToken = this.session.rawToken;
/* ... */
}
}


I have found a workaround to wrap my this.fetchUser() call with setTimeout(() => this.fetchUser(), 0), but why do I have to postpone this to another turn of event loop? That is my question. Please tell me, what rule am I violating?










share|improve this question

























  • Sounds like your sessions service hasn't be instantiated yet by the time it's called in your service. At what point of your applications lifecycle does that happen? It's definitely a timing issue.

    – Mickers
    Nov 21 '18 at 20:49











  • @Mickers I've suddenly realized why this happens. Its because I do an http request in my SessionService constructor and my http interceptor is called synchronously for that request, but I haven't escaped my SessionService constructor function yet. Yeah, that was unexpected. My SessionService and JwtInterceptor just have implicit circular dependency through the HttpClient.

    – Veetaha
    Nov 21 '18 at 20:54













  • Glad that helped

    – Mickers
    Nov 21 '18 at 20:56
















0















I have a SessionService which manages JWT token and stores user data. When my app is started I need to fetch user data from backend via http. It might be a bad idea, but since there is no ngOnInit() for services I do it in SessionService constructor:



@Injectable({
providedIn: 'root'
})
export class SessionService {
constructor(
private errHandler: ErrorHandlingService,
private backend: UsersService
) {
const initialToken = this.rawToken; // localStorage.getItem('jwt')
if (!initialToken || this.isTokenExpired(initialToken)) {
localStorage.removeItem('jwt');
return;
}
this.fetchUser();
}

private fetchUser() {
this.backend.getMe().subscribe(
user => this.user = user,
err => this.errHandler.handle(err)
);
}
/* ... */
}


I think this is pretty straightforward, UsersSevice::getMe() is just an abstraction for:



    getMe() {
return this.http.get<Api.V1.Me.Get.Response>('/api/v1/me');
}


The problem is that my HttpInterceptor that attaches JWT to the header of each http request, that it obtains via my SessionServicegets this service as undefined, so the TypeError is raised when accessing its rawRoken getter (can not read property rawToken of undefined)



@Injectable()
export class JwtInterceptor implements HttpInterceptor {

constructor(private session: SessionService) {}

intercept(req: HttpRequest<unknown>, next: HttpHandler) {
const rawToken = this.session.rawToken;
/* ... */
}
}


I have found a workaround to wrap my this.fetchUser() call with setTimeout(() => this.fetchUser(), 0), but why do I have to postpone this to another turn of event loop? That is my question. Please tell me, what rule am I violating?










share|improve this question

























  • Sounds like your sessions service hasn't be instantiated yet by the time it's called in your service. At what point of your applications lifecycle does that happen? It's definitely a timing issue.

    – Mickers
    Nov 21 '18 at 20:49











  • @Mickers I've suddenly realized why this happens. Its because I do an http request in my SessionService constructor and my http interceptor is called synchronously for that request, but I haven't escaped my SessionService constructor function yet. Yeah, that was unexpected. My SessionService and JwtInterceptor just have implicit circular dependency through the HttpClient.

    – Veetaha
    Nov 21 '18 at 20:54













  • Glad that helped

    – Mickers
    Nov 21 '18 at 20:56














0












0








0








I have a SessionService which manages JWT token and stores user data. When my app is started I need to fetch user data from backend via http. It might be a bad idea, but since there is no ngOnInit() for services I do it in SessionService constructor:



@Injectable({
providedIn: 'root'
})
export class SessionService {
constructor(
private errHandler: ErrorHandlingService,
private backend: UsersService
) {
const initialToken = this.rawToken; // localStorage.getItem('jwt')
if (!initialToken || this.isTokenExpired(initialToken)) {
localStorage.removeItem('jwt');
return;
}
this.fetchUser();
}

private fetchUser() {
this.backend.getMe().subscribe(
user => this.user = user,
err => this.errHandler.handle(err)
);
}
/* ... */
}


I think this is pretty straightforward, UsersSevice::getMe() is just an abstraction for:



    getMe() {
return this.http.get<Api.V1.Me.Get.Response>('/api/v1/me');
}


The problem is that my HttpInterceptor that attaches JWT to the header of each http request, that it obtains via my SessionServicegets this service as undefined, so the TypeError is raised when accessing its rawRoken getter (can not read property rawToken of undefined)



@Injectable()
export class JwtInterceptor implements HttpInterceptor {

constructor(private session: SessionService) {}

intercept(req: HttpRequest<unknown>, next: HttpHandler) {
const rawToken = this.session.rawToken;
/* ... */
}
}


I have found a workaround to wrap my this.fetchUser() call with setTimeout(() => this.fetchUser(), 0), but why do I have to postpone this to another turn of event loop? That is my question. Please tell me, what rule am I violating?










share|improve this question
















I have a SessionService which manages JWT token and stores user data. When my app is started I need to fetch user data from backend via http. It might be a bad idea, but since there is no ngOnInit() for services I do it in SessionService constructor:



@Injectable({
providedIn: 'root'
})
export class SessionService {
constructor(
private errHandler: ErrorHandlingService,
private backend: UsersService
) {
const initialToken = this.rawToken; // localStorage.getItem('jwt')
if (!initialToken || this.isTokenExpired(initialToken)) {
localStorage.removeItem('jwt');
return;
}
this.fetchUser();
}

private fetchUser() {
this.backend.getMe().subscribe(
user => this.user = user,
err => this.errHandler.handle(err)
);
}
/* ... */
}


I think this is pretty straightforward, UsersSevice::getMe() is just an abstraction for:



    getMe() {
return this.http.get<Api.V1.Me.Get.Response>('/api/v1/me');
}


The problem is that my HttpInterceptor that attaches JWT to the header of each http request, that it obtains via my SessionServicegets this service as undefined, so the TypeError is raised when accessing its rawRoken getter (can not read property rawToken of undefined)



@Injectable()
export class JwtInterceptor implements HttpInterceptor {

constructor(private session: SessionService) {}

intercept(req: HttpRequest<unknown>, next: HttpHandler) {
const rawToken = this.session.rawToken;
/* ... */
}
}


I have found a workaround to wrap my this.fetchUser() call with setTimeout(() => this.fetchUser(), 0), but why do I have to postpone this to another turn of event loop? That is my question. Please tell me, what rule am I violating?







angular angular-services angular-httpclient angular-http-interceptors angular7






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 19:49







Veetaha

















asked Nov 21 '18 at 19:38









VeetahaVeetaha

101111




101111













  • Sounds like your sessions service hasn't be instantiated yet by the time it's called in your service. At what point of your applications lifecycle does that happen? It's definitely a timing issue.

    – Mickers
    Nov 21 '18 at 20:49











  • @Mickers I've suddenly realized why this happens. Its because I do an http request in my SessionService constructor and my http interceptor is called synchronously for that request, but I haven't escaped my SessionService constructor function yet. Yeah, that was unexpected. My SessionService and JwtInterceptor just have implicit circular dependency through the HttpClient.

    – Veetaha
    Nov 21 '18 at 20:54













  • Glad that helped

    – Mickers
    Nov 21 '18 at 20:56



















  • Sounds like your sessions service hasn't be instantiated yet by the time it's called in your service. At what point of your applications lifecycle does that happen? It's definitely a timing issue.

    – Mickers
    Nov 21 '18 at 20:49











  • @Mickers I've suddenly realized why this happens. Its because I do an http request in my SessionService constructor and my http interceptor is called synchronously for that request, but I haven't escaped my SessionService constructor function yet. Yeah, that was unexpected. My SessionService and JwtInterceptor just have implicit circular dependency through the HttpClient.

    – Veetaha
    Nov 21 '18 at 20:54













  • Glad that helped

    – Mickers
    Nov 21 '18 at 20:56

















Sounds like your sessions service hasn't be instantiated yet by the time it's called in your service. At what point of your applications lifecycle does that happen? It's definitely a timing issue.

– Mickers
Nov 21 '18 at 20:49





Sounds like your sessions service hasn't be instantiated yet by the time it's called in your service. At what point of your applications lifecycle does that happen? It's definitely a timing issue.

– Mickers
Nov 21 '18 at 20:49













@Mickers I've suddenly realized why this happens. Its because I do an http request in my SessionService constructor and my http interceptor is called synchronously for that request, but I haven't escaped my SessionService constructor function yet. Yeah, that was unexpected. My SessionService and JwtInterceptor just have implicit circular dependency through the HttpClient.

– Veetaha
Nov 21 '18 at 20:54







@Mickers I've suddenly realized why this happens. Its because I do an http request in my SessionService constructor and my http interceptor is called synchronously for that request, but I haven't escaped my SessionService constructor function yet. Yeah, that was unexpected. My SessionService and JwtInterceptor just have implicit circular dependency through the HttpClient.

– Veetaha
Nov 21 '18 at 20:54















Glad that helped

– Mickers
Nov 21 '18 at 20:56





Glad that helped

– Mickers
Nov 21 '18 at 20:56












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53419405%2fangular-service-is-undefined-when-fetching-backend-data-in-its-constructor%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53419405%2fangular-service-is-undefined-when-fetching-backend-data-in-its-constructor%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

How to fix TextFormField cause rebuild widget in Flutter