Home > Blockchain >  Return context data from time of request with response in Typescript async http call
Return context data from time of request with response in Typescript async http call

Time:09-16

I have this async method inside an Angular service:

public async getListings() {

    // generate path, body, headers

    return await this.http.post<any>(path, body, headers)
    .pipe(
        catchError(this.handleError)
    ).toPromise()
}

I have this setup in an Angular component:

ngOnInit(): void {

    this.loadThree();

    var self = this;
    setInterval(function () {
        if ((self.container.scrollHeight - (self.scrollWindow.scrollTop   self.scrollWindow.clientHeight) < 1000) {
            if (!self.loading) {
                self.loading = true;
                self.getPages()
                self.loading = false;
            }
        }
    }, 1000)
}

public async loadThree() {
    this.loading = true;
    for(var i = 0; i < 3; i   ) {
      await this.getPages()
    }
    this.loading = false;
}

public async getPages() {
    // ....
    var postResponse = await this.<servicename>.getListings();
    // ...
}

The idea is that I generate 3 pages when the site loads, then register an interval to check if the user has scrolled within 1000px of the bottom of the div. If he has, I make the next API call to pull another page.

If the user does a search for new parameters, I clear the results, but it's possible I have already made a request to load a page for old parameters, and those will then be added to the results from the new parameters when the API returns. I'm looking for a way to check if the request is old, so I can ignore the results in the component.

CodePudding user response:

I'm gonna be brave and code this off the top of my head:

interface IPayload {
  path: string,
  body: any,
  headers: any
}

@Injectable({ providedIn: 'root' })
export class MissionService {

  // Observable sources
  private missionAnnouncedSource = new Subject<IPayload>();

  // Observable streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable().pipe(
    // switchMap here will auto abort old requests if the request has not completed by the time a new request is made
    // you can see the aborts in network tab devtools
    switchMap((payload: IPayload) => {
      return this.http.post<any>(payload.path, payload.body, payload.headers).pipe(
        catchError(() => of(null))
      )
    })
  );

  // call this to make new HTTP request
  makeNewRequest(path: string, body: any, headers: any) {
    const payload: IPayload = {path, body, headers}
    this.missionAnnouncedSource.next(payload)
  }
}

Then in your component subscribe as follows:

constructor(private missionService: MissionService) {}

ngOnInit(): void {
  this.missionService.missionAnnounced$.subscribe((upToDateStuff: any) => {
     if (upToDateStuff != null) {
       console.log( upToDateStuff )
     } else {
       console.log( 'something went wrong' )
     }        
  })
}

CodePudding user response:

I found a solution in adapting how I was doing the call. I stopped returning the promise from the service, and instead return the observable:

public getListings() {

    // generate path, body, headers

    return this.http.post<any>(path, body, headers)
    .pipe(
        catchError(this.handleError)
    )
}

Then in the component, I subscribe to it:

public serviceSub: Subscription;

public getPages() {
     this.serviceSub = this.<serviceName>.getListings()
        .subscribe(
          data => {
            console.log(data)
          },
          error => {
            console.log(error)
          }
        )
    } catch (error) {
      console.log("Problem happened")
    }
}

That way, when my user runs another search with new params I can forget any request that was made before he searched by, as he hits search, calling unsubscribe:

this.serviceSub.unsubscribe();

Any input is welcome, thanks!

  • Related