Home > Software design >  http API request Angular 12 is empty on the HTML page
http API request Angular 12 is empty on the HTML page

Time:09-16

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);

enter image description here

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.

  1. 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);
    }
  );
}
  • Related