1

This might be a basic question. but I am new to angular services(promises,observable etc).

basically, I have a button(login) in login page , once user clicks on that button I want to validate and generate token. once the token is assigned field on service, then I will redirect to some page(Home page). But what is happening now is, when I made a function call to angular service function, before it gets(asynchronously) the token itself my page is redirecting.


app-data-service

`

    import { Injectable } from '@angular/core';
    import { HttpClient,HttpHeaders } from '@angular/common/http';
    import 'rxjs/add/operator/map';
    import 'rxjs/add/operator/mergeMap';
    import 'rxjs/add/operator/toPromise';
    @Injectable()
    export class AppDataServiceService {
      tokenGenerated:any='';
      constructor(private http: HttpClient) { 

      }

      getData(){
        console.log("Started.. in service");
         this.http.get('http://host/url').toPromise()
         .then(this.extractData);

      }
      private extractData(res: Response) {
        console.log("completed.. in service");
        this.tokenGenerated=res;
        return res;
    }

    }
    `---------------------------------------------------
    login component

    import { Component, OnInit } from '@angular/core';
    import { AppDataServiceService } from '../app-data-service.service';
    import { Router } from '@angular/router';

    @Component({
      selector: 'app-login-component',
      templateUrl: './login-component.component.html',
      styleUrls: ['./login-component.component.css']
    })
    export class LoginComponentComponent implements OnInit {

      constructor(private dataService:AppDataServiceService,private router:Router) {

       }

      ngOnInit() {
      }

      submit(){
        this.dataService.getData();
        console.log('after executing service');
        this.router.navigate(['/view']);
      };

    }
-------------------------------------------------------------
   login html

<div class="container">
  <label><b>Username</b></label>
  <input type="text" placeholder="Enter Username" name="uname" >

  <label><b>Password</b></label>
  <input type="password" placeholder="Enter Password" name="psw" >



</div>

<input type="button" (click)='submit()'  value="Login"  name="submit"/>

console output in browser:

Started.. in service

after executing service

completed.. in service

Can you help me to let http call wait till its completion. I am not sure if that is the way to use promise to make the call synchronous.

1
  • . use this.router.navigate(['/view']); inside the promise resolver inside component and return the Promise from your service class Commented Jan 5, 2018 at 18:40

2 Answers 2

7

You should return a promise (or Observable) from your service, and subscribe to that in the component.

Without doing so, the component has no way of knowing when your asynchronous code has finished executing, so it prints that log statement immediately

Change the service like so:

getData(){
    console.log("Started.. in service");
    return this.http.get('http://host/url').toPromise()
        .then(res => this.extractData(res));
}

Then in the component

submit(){
    this.dataService.getData().then(() => {
        console.log('after executing service');
        this.router.navigate(['/view']);
    };
};
Sign up to request clarification or add additional context in comments.

5 Comments

i was just talking about this.. The same can be done using Observable , not sure why the OP is converting it to Promise
Thanks user184994. after the modifying the above code I was getting some error. Error: Uncaught (in promise): TypeError: this is undefined. The url that I am using for testing is "jsonplaceholder.typicode.com/users". just for testing. Not sure what is the issue.
@user12 On which line / in which file? And in what way did you modify the code?
@user184994, when assigning this.tokenGenerated=res; the response is list of objects. is that a issue ? when I comment this line it is working fine. I modified declaration, tokenGenerated:any=[]; but still the same issue.
I've made a change, try that. It's because the context of this is lost. By using fat arrow syntax (=>), we can retain the context. The other alternative is to write .then(this.extractData.bind(this));, but I find the former syntax nicer
1

Use synchronous http request as below

var request = new XMLHttpRequest();
request.open('GET', "https://domain/api", false);  
request.send(null);
const response = JSON.parse(request.responseText); 

Would not be able to take advantage of DI using HttpClient and hence should be used absolutely when required.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.