Reputation: 1967
I am having Angular 2 Typescript application. I want to access Build Artifacts from Jenkins server using Jenkins Rest API in my application. The Build Artifact conatins one text file. I want to read the text from the file. I am using http.get() from angular to access the jenkins url. The responseType returned is text() as the file contains some text. When I try to assign the response returned to the variable (this.data) defined in my component,I dont see any value assigned to it.
//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 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);
// console.log(this.data);-- It shows undefined. No values seen
}
}
getValueFromJenkins(serviceName) {
this._jenkinsService.getTextFromJenkins(this.serviceName).subscribe(
textdata=> this.data= <string>textdata,
// textdata=> console.log(textdata) -- here I can see the text values.
error => this.errorMessage = <any>error from server
);
//console.log(this.data); --here I dont see any text values
}
Upvotes: 0
Views: 575
Reputation: 40936
In your ngOnInit
, when you make the call to getValueFromJenkins
, the response doesn't arrive right away. That's why on the next line this.data
is still undefined. The response arrives later, inside the .subscribe()
. You have at least 3 options:
Angular allows you to use a special service called a Resolve Guard that will fetch asynchronous data during the route loading process and will initialize your component only after the data has arrived. The benefit of this is that the data will be available synchronously whithin ngOnInit()
, so there will be no lag between component load and data load, and no fuss dealing with asynchronous operations. This is probably the best solution but it requires modifying your route configs and writing a new Service class. See the docs
In ngOnInit
, you could wait until the data returns to use it:
this._jenkinsService.getTextFromJenkins(this.serviceName).subscribe(
result => this.data = result // note this happens later, once server returns data
);
The async/await keywords allow you to work with asynchronous code as if it were synchronous, by forcing the browser to wait for execution to resolve before moving on to the next line. To implement this approach, first change getValueFromJenkins()
and make it return a promise:
getValueFromJenkins(serviceName):Promise {
// will subscribe and convert the result to a promise that will resolve
// with the server's response
return this._jenkinsService.getTextFromJenkins(serviceName).toPromise();
}
Next, mark ngOnInit
as async
; you can get the data like so:
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 work!
}catch(e) { /* Handle error here */}
}
}
Upvotes: 1