I'm a little bit confused while trying to make a call to an API. I first created a service that is calling the API:
public getCategories(): Observable<any> {
let getCategoriesUrl = 'http://localhost:4300/WS/GetCategories';
return this.http.get<any>(getCategoriesUrl, {
headers: this.httpOptions, responseType: 'text' as 'json'
});
}
In my component I have a method that retrieves the data. My data is not clean that's why do clean special caracters that are returned. That's also why in my service i do not retrieve an observable of a specific model but of 'any'. Here is the implementation.
private getCategories() {
this.soapService.getCategories().subscribe(
(res) => {
console.log(typeof res);
res = res.replace(/\n/g, '');
this.replacement.forEach(
item => {
res = res.replace(item, '');
}
);
// res is a string with all data from API call => parsing string to object
// console.log(res);
this.categoriesResponseModel = JSON.parse(res);
console.log('iterate after string parsing');
// @ts-ignore
for (const category of this.categoriesResponseModel.CATEGORIES) {
// console.log(category);
this.categories.push(category);
}
console.log("In get categories");
console.log("Output ", this.categories);
},
(err) => {
console.log(err.message);
},
() => {
console.log('Completed - Categories pushed');
}
);
}
In the method output is printed with the expected values on the line containing the following console.log: console.log("Output ", this.categories);
ngOnInit() {
console.log('# ngOnInit() called');
this.getCategories();
console.log(this.categories)
console.log("output " this.categories)
}
In the ngOnInit i do have an empty array as output. I test to display the result in the HTML page:
{{ categories.length }}
<div *ngFor="let category of categories">
{{ category.CategoryID }} - {{ category.CategoryName }}: {{ category.DocDescription }}
</div>
I obtain length equals to 0 unfortunatelly.
CodePudding user response:
Instead of this:
// @ts-ignore
for (const category of this.categoriesResponseModel.CATEGORIES) {
// console.log(category);
this.categories.push(category);
}
you should try this:
this.categories = [...this.categoriesResponseModel.CATEGORIES];
CodePudding user response:
Two things
1.
ngOnInit() {
console.log('# ngOnInit() called');
this.getCategories();
console.log(this.categories)
console.log("output " this.categories)
}
Here console.log(this.categories)
might be undefined
due to async assignment inside the subscription. See this canonical post on async data.
- Pushing to an array doesn't trigger Angular change detection. In this case, you could directly assign to the variable.
this.categories = this.categoriesResponseModel.CATEGORIES;
instead of
// console.log(category);
this.categories.push(category);
}
CodePudding user response:
I've been inspired by Octavian Mărculescu proposal to use ChangeDetectorRef. Here is my updated code for getCategories in the component.
I also changed the place i call the getCategories and placed it in the constructor
constructor(@Inject(TRANSLATION) public readonly lang: Translation,
private cd: ChangeDetectorRef,
private soapService: SoapApiService,
private route: ActivatedRoute) {
this.getCategories();
}
Here is the implementation:
getCategories(): void {
const values: CategoryModel[] = [];
const response = this.soapService.getCategories().subscribe(
(res) => {
console.log(typeof res);
res = res.replace(/\n/g, '');
this.replacement.forEach(
item => {
res = res.replace(item, '');
}
);
// res is a string with all data from API call => parsing string to object
// console.log(res);
this.categoriesResponseModel = JSON.parse(res);
console.log('iterate after string parsing');
// @ts-ignore
for (const category of this.categoriesResponseModel.CATEGORIES) {
// console.log(category);
values.push(category);
}
this.cd.markForCheck();
},
(err) => {
console.log(err.message);
},
() => {
console.log('Completed - Categories pushed');
this.categories = values;
console.log(this.categories);
}
);
}