The class variable cannot access the Angular Http response returned by the service

I have a Typescript application built with Angular 2. In this application, I need to retrieve Build Artifacts from a Jenkins server using the Jenkins Rest API. The Build Artifact contains a text file that I want to read from. I am making use of Angular's http.get() method to access the Jenkins URL. The response type I am expecting is text() since the file contains text. However, when I try to assign the response to a variable (this.data) in my component, the value does not get assigned.

//myservice.ts
import { Http, Response } from '@angular/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { AppConfig } from '../app.config';

@Injectable()
export class JenkinsService {
  private jenkinsRestAPI;
  constructor(private http: Http, private config: AppConfig) {
  }
  getTextFromJenkins(serviceName): Observable<string>{   
    this.jenkinsRestAPI= 'http://'+this.config.getConfig('jenkins')+'/job/'+serviceName
    return this.http.get(this.jenkinsRestAPI)
      .map(this.extractData)
      .catch(this.handleError); 
  }

  // Extracts data from response
  private extractData(res: Response) {
    if (res.status < 200 || res.status >= 300) {
      throw new Error('Bad response status: ' + res.status);
    }    
    let body = res.text();
    return body || ''; // here
  }

//mycomponent.ts
export class JenkinsComponent implements OnInit {
  servicesList:Array<string> = ['Backend','DataService', 'demoService','SystemService']
  data:string;
  errorMessage: string;
  serviceName:string;

  constructor(private _jenkinsService: JenkinsService) {      
  }

  ngOnInit() {
    for(var i = 0; i < this.servicesList.length; i++){
      this.serviceName=this.servicesList[i];
      this.getValueFromJenkins(this.serviceName);
    } 
  }

  getValueFromJenkins(serviceName) {
    this._jenkinsService.getTextFromJenkins(this.serviceName).subscribe(
      textdata=> this.data= <string>textdata, 
      error => this.errorMessage = <any>error from server
    );
  }

Answer №1

When you call getValueFromJenkins in your component's ngOnInit, the response does not arrive immediately. This is why this.data is still undefined in the next line. The response actually arrives later, within the .subscribe() method. Here are three options you can consider:

Utilize a Data Resolve Guard

Angular provides a Resolve Guard service that fetches asynchronous data during route loading and initializes your component only after the data is ready. This ensures that the data is available synchronously within ngOnInit(), eliminating any delay between component and data loading. Although this solution is more complex as it involves modifying route configurations and creating a new service class, it is considered one of the best approaches. Check out the documentation

Subscribe within ngOnInit

In the ngOnInit method, you can simply wait for the data to return before using it:

this._jenkinsService.getTextFromJenkins(this.serviceName).subscribe(
   result => this.data = result // data assignment occurs after server response
);

Implement async/await for Synchronous Behavior

Using the async/await keywords allows you to work with asynchronous code in a synchronous manner. By utilizing async/await, you force the browser to wait for the code execution to resolve before progressing to the next line. To apply this concept, modify getValueFromJenkins() to return a promise:

getValueFromJenkins(serviceName): Promise {
  // Subscribe and convert the result to a promise that resolves with the server response
  return this._jenkinsService.getTextFromJenkins(serviceName).toPromise();
}

Then, designate ngOnInit as async and retrieve the data as follows:

async ngOnInit() {
  for(let i = 0; i < this.servicesList.length; i++){
    try{
      this.data = await this.getValueFromJenkins(this.servicesList[i]);
      console.log(this.data); // should be accessible now!
    } catch(e) { /* Handle any errors here */}
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Prevent Duplicate Service Instances in Angular

After doing some thorough research online, I've identified the root of my issue: multiple instances of a particular service are being created. I need assistance in pinpointing and rectifying this problem within my code. The secondary service is depen ...

Using TypeScript with Next.js getStaticProps causes errors

Currently, I am grappling with utilizing getStaticProps along with TypeScript. Initially, I attempted to achieve this using a function declaration: import { Movie } from './movies/movie' import { GetStaticProps } from 'next' export asy ...

Error encountered during installation of Nativescript Post Install Script

While I am comfortable running one of our current projects with Nativescript, I encountered an error when attempting to install it on a new project using the following command: sudo ng new --collection=@nativescript/schematics the-juice-box --shared The ...

Angular binding of variable names beginning with numbers

Currently in my Angular 4 project, I am utilizing the interpolation syntax below: {{variable.24h_volume}} Upon implementation, an error is thrown stating: Unexpected token '0.24' at column 5 in [{{variable.24h_volume}}] in ng:///AppModule/Comp ...

Preventing Repeated Form Submissions in Angular: A Helpful Guide

`Hello, I am new to Angular and I am struggling with a specific part of the form. People have been clicking the submit button multiple times quickly, causing the same information to be added repeatedly before it can be sent to the API. I have searched onl ...

TS2531: Nullability detected in object when using .match() method

I'm encountering a linting error on fileNameMatches[0] in the following code snippet. Strangely, the error doesn't appear on the Boolean() check. Even if I remove that check, the issue remains unresolved. Can anyone suggest a solution? protected ...

When working with the Google Sheets API, an error occurred: "this.http.put(...).map is not a valid

Having difficulty with a straightforward request to the Google Sheets API using the PUT method. I followed the syntax for http.put, but an error keeps popping up: this.http.put(...).map is not a function. Here's my code snippet: return this.http ...

Angular2 Cascading Dropdowns

When using Angular2, I am interested in creating a cascading select for the array object provided with values of xs and ys: data:Array<Object> = [ {"x":50, "ys":[ 10, 15, 20, 25, 30, 35]}, ...

Having trouble with your React/TypeScript/Redux/Thunk action not dispatching and the state remaining unchanged?

Currently, I am facing an issue while attempting to send a GET request to an API using React-Redux & TypeScript. The goal is to dispatch an action upon clicking a button (onClick event), make the request, update the state via the reducer, and finally log t ...

Struggling to retrieve the value of a text field in Angular with Typescript

In the Angular UI page, I have two types of requests that I need to fetch and pass to the app.component.ts file in order to make a REST client call through the HTML page. Request 1: Endpoint: (GET call) http://localhost:8081/api/products?productId=7e130 ...

Spring Security OAuth - redirecting to the client application

Creating an API with Spring secured by Oauth2 was successful. The configuration file for Facebook is as follows: clientId: xxx clientSecret: xxxx accessTokenUri: https://graph.facebook.com/oauth/access_token userAuthorizationUri: https://www.facebook.com/ ...

Tips for avoiding the influence of the parent div's opacity on child divs within a Primeng Carousel

I'm struggling to find a solution to stop the "opacity" effect of the parent container from affecting the child containers. In my code, I want the opacity not to impact the buttons within the elements. I have tried using "radial-gradient" for multipl ...

Guide to populating a list in a resolver during navigation and storing the initial item in the ngrx store

I recently incorporated ngrx into my application to manage the data centrally. However, I am facing challenges with loading the initial data and navigating to a default value. This has raised questions regarding the best approach to utilizing ngrx while re ...

Troubleshooting: Bootstrap not functioning in Angular with Webpack due to vendor bundle issue

Bootstrap is included in my vendor.js bundle, as shown in the snapshot below, https://i.stack.imgur.com/q5k8c.png Upon inspecting the DOM, it's clear that bootstrap classes are being applied too, as seen in the snapshot below, https://i.stack.imgur. ...

The Clerk middleware is causing delays in loading, leading to a 504 Error on NextJS / Vercel with the message 'FUNCTION_INVOCATION_TIMEOUT'

I'm currently working on a web page where I need to utilize Clerk for authentication and login. However, I've encountered an issue with the middleware taking too long to load, causing deployment problems for the app. Here is the code from middle ...

Troubleshooting Angular 2 component tests using Jasmine spies: How to resolve the "Http provider not found" error

I'm currently testing an Angular 2 component that utilizes a service. The service has Http injected into it, but I'm only interested in mocking and spying on the service's method call rather than testing the Http functionality itself. While ...

Enhancing interface properties with type safety in a function declaration using Typescript

Consider the following scenario: interface Steps { stepOne?: boolean; stepTwo?: boolean; stepThree?: boolean; } let steps: Steps = {}; function markStepDone (step: ???) { steps[step] = true; } markStepDone('anything'); Is there a wa ...

What are the distinctions between using findById({_id:historyId}) and findById(historyId) in Mongoose?

While working on one of my projects, I encountered a situation that left me a bit confused. I am trying to understand if both approaches outlined below will yield the same output, and if so, why? async getHistory( historyId: string) { const { h ...

Issue encountered when attempting to assign a local variable as the initial value of an enum object member

Check out this playground link for a TypeScript example. I'm having issues setting the initial value of an enum member using a constant numeric value. Unfortunately, all subsequent values give an error stating "Enum member must have initializer." Is ...

Obtain information from a web address using Ionic framework

Hello, I am experiencing an issue with retrieving data from a URL in my Ionic application. When using @angular/http to fetch a JSON object from the URL, everything works fine in the browser when running 'ionic serve'. However, when deploying the ...