Issue
I'm new to Angular and I want to build a frontend application that consume my REST API (built with Django). I have searched since two days but I cannot get a satisfying answer to my question. I tried to ask Chat GPT but it seems like it's always busy (can't access after I logged in). I have created a services and models to make everything comfortable but it doesn't work.
I trying to load API data into several lists in my HomeComponent.
Here is my model:
export interface ProductList{
total_pages: number;
current_page: number;
has_next: boolean;
has_prev: boolean;
page_items_count: number;
items_per_page: number;
data: [
id: number,
name: string,
picture: string,
price: number,
discount: number | null,
saved_amount: number,
discount_percent: number | null,
slug: string,
is_available: boolean,
ratings_average: number,
ratings_count: number,
date: string,
uuid: string,
extra_data: any,
category: Category,
]
}
export interface ProductDetail{} // For now, I haven't designed ProductDetail model. Just declared it.
My Service
import { Injectable } from '@angular/core';
import { Observable, catchError, of, map } from 'rxjs';
import { ProductList, ProductDetail } from '../../models/products.models';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ProductsService {
baseUrl = "http://127.0.0.1:8000/api";
headers = new HttpHeaders({
'Content-Type': 'application/json',
});
constructor(private http: HttpClient) { }
private handleError(error: Error, errorValue: any) {
return of(errorValue);
}
getProductList(): Observable<ProductList[]> {
const productUrl = `${this.baseUrl}/products/`
return this.http.get<ProductList[]>(productUrl, { headers: this.headers }).pipe(
catchError((error) => this.handleError(error, []))
);
}
getProductDetail(product_id: number): Observable<ProductDetail|undefined> {
const productDetaiLlUrl = `${this.baseUrl}/products/${product_id}/`
return this.http.get<ProductDetail>(productDetaiLlUrl, { headers: this.headers }).pipe(
catchError((error) => this.handleError(error, undefined))
);
}
getUnavailableProductList(): Observable<ProductList[]> {
const productUrl = `${this.baseUrl}/products/unvailable/`
return this.http.get<ProductList[]>(productUrl, { headers: this.headers }).pipe(
catchError((error) => this.handleError(error, []))
);
}
searchProducts(query: string|null): Observable<ProductList[]> {
const params = query ? new HttpParams().set('q', query): {}
const searchUrl = `${this.baseUrl}/products/search/`
return this.http.get<ProductList[]>(searchUrl, { params: params, headers: this.headers }).pipe(
catchError((error) => this.handleError(error, []))
);
}
}
My HomeComponent
import { Component, OnInit } from '@angular/core';
import { ProductList } from '../../models/products.models';
import { ProductsService } from 'src/app/services/products/products.service';
@Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
public productList: ProductList[];
products = [];
public total_pages: number;
public current_page: number;
public has_next: boolean;
public has_prev: boolean;
public page_items_count: number;
public items_per_page: number;
public _products = []
constructor (private productService: ProductsService) {}
ngOnInit() {
this.productService.getProductList().subscribe((res) => {
this.productList = res;
// Here, I want to load values of the key "data" (a list of products) into this.productList
// And also the value of key "total_pages" in this.total_pages and so on (for the rest of the other variables that I declared.
});
}
}
Well, when I send the GET request, I'm receiving correct data but I can't loop through that data.
If I do *ngFor="let product of productList.data"
it shows an error. For some reason, I want to access all of these data separately.
With console.log(this.productList)
, the entire response is loaded but I only want to access products from key "productList.data" and display them. But the problem is that I can't load data separately and can't also loop through "productList.data" to get products.
Below is the schema of response when I send a GET request to products (the key "data" is a list of products) Response schema
So how can I get those data, load them in different lists and send them to my HTML view ?
Solution
SOLVED
When I send a request to my backend, it doesn't return a list of products but an object containing a list of products (with data
key: "data": []
So instead of tell to ProductService to return a list of products, I changed into an object. And this object contains a list of products like I said.
So here are my new models: products.models.ts
export interface Product{
id: number;
name: string;
picture: string;
price: number;
discount: number | null;
saved_amount: number;
discount_percent: number | null;
slug: string;
is_available: boolean;
date: string;
ratings_average: number;
ratings_count: number;
uuid: string;
extra_data: any;
category: Category;
}
export interface ProductObject{
total_pages: number;
current_page: number;
has_next: boolean;
has_prev: boolean;
page_items_count: number;
items_per_page: number;
data: Product[]; // products are available here in "data" key
}
My new products.services.ts
import { Injectable } from '@angular/core';
import { Observable, catchError, of } from 'rxjs';
import { ProductObject, ProductDetailObject } from '../../models/products.models';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ProductsService {
baseUrl = "http://localhost:8000/api";
headers = new HttpHeaders({
'Content-Type': 'application/json',
});
constructor(private http: HttpClient) { }
private handleError(error: Error, errorValue: any) {
return of(errorValue);
}
getProductList(): Observable<ProductObject> {
const productUrl = `${this.baseUrl}/products/`
return this.http.get<ProductObject>(productUrl, { headers: this.headers }).pipe(
catchError((error) => this.handleError(error, []))
);
}
getProductDetail(product_id: number): Observable<ProductDetailObject|undefined> {
const productDetaiLlUrl = `${this.baseUrl}/products/${product_id}/`
return this.http.get<ProductDetailObject>(productDetaiLlUrl, { headers: this.headers }).pipe(
catchError((error) => this.handleError(error, undefined))
);
}
getUnavailableProductList(): Observable<ProductObject> {
const productUrl = `${this.baseUrl}/products/unvailable/`
return this.http.get<ProductObject>(productUrl, { headers: this.headers }).pipe(
catchError((error) => this.handleError(error, []))
);
}
searchProducts(query: string|null): Observable<ProductObject> {
const params = query ? new HttpParams().set('q', query): {}
const searchUrl = `${this.baseUrl}/products/search/`
return this.http.get<ProductObject>(searchUrl, { params: params, headers: this.headers }).pipe(
catchError((error) => this.handleError(error, []))
);
}
}
As you can see, I'm returning now an object of my API response.
So I found the correct/perfect way to answer my question (How to load Angular GET request response data into different lists?)
I can now restructure data that I got from my service and load data into different variables.
So here is how my homepage.component.ts looks now:
import { Component, OnInit } from '@angular/core';
import { ProductObject, Product } from '../../models/products.models';
import { ProductsService } from 'src/app/services/products/products.service';
@Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
constructor (private productService: ProductsService) {}
// PRODUCTS vars
productObject: ProductObject;
products: Product[];
productsTotalPages: number;
productsCurrentPage: number;
productsHasNext: boolean;
productsHasPrev: boolean;
productsPageItemsCount: number;
productsItemsPerPage: number;
ngOnInit() {
// GET products data
this.productService.getProductList().subscribe((productsData) => {
this.productObject = productsData;
this.products = productsData.data;
this.productsTotalPages = productsData.total_pages;
this.productsCurrentPage = productsData.current_page;
this.productsHasNext = productsData.has_next;
this.productsHasPrev = productsData.has_prev;
this.productsPageItemsCount = productsData.page_items_count;
this.productsItemsPerPage = productsData.items_per_page;
});
}
}
I can now iterate over my products
in my HTML template.
Answered By - Stefan-ci
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.