Reputation: 53
Ive been having trouble with Angular 8 recently trying to create a simple web application to improve my skils. I'm trying to make a table web app, the html for the table looks like such and uses the product array thats populated from the service in the component class.
<table class = "table" *ngIf = "Products && Products.length!=0">
<thead>
<tr>
<th>
<!-- ternary statement to change the image text -->
<button class = "btn btn-primary" (click)= 'toggleImage()'>{{ showImage ? 'Hide Image' : 'Show Image'}}</button>
</th>
<th>Product</th>
<th>Code</th>
<th>Available</th>
<th>Description</th>
<th>Price</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
<tr *ngFor = "let product of filteredProducts">
<td>
<!-- //the image will only show if show image is true -->
<img *ngIf = 'showImage'
[src]='product.imageUrl'
[title]='product.productName | uppercase'
[style.width.px]= 'imageWidth'
[style.margin.px]="imageMargin">
</td>
<td>{{product.productName}}</td>
<td>{{product.productCode | lowercase | convertToSpaces: '-'}}</td>
<td>{{product.releaseDate}}</td>
<td>{{product.description}}</td>
<td>{{product.price | currency: 'EUR'}}</td>
<td><pm-star [rating]= "product.starRating" (ratingClicked)= "onRatingClicked($event)"></pm-star></td>
</tr>
</tbody>
</table>
I wrote a service class which looks like this
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, tap, map } from 'rxjs/operators'
import { IProduct } from '../../app/components/product-list/product';
@Injectable({
providedIn: 'root'
})
export class ServiceService{
private productUrl = "http://localhost:4200/assets/data.json"
constructor(private http: HttpClient) { }
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productUrl)
.pipe(
tap(data => console.log('All: ' + JSON.stringify(data))),
catchError(this.handleError));
}
}
The service contains a getProducts function that returns an observable from the json data which is just a local file and also prints the data to the console.
The JSON file contains multiple objects such as
{
"productId": 5,
"productName": "Hammer",
"productCode": "TBX-0048",
"releaseDate": "May 21, 2019",
"description": "Curved claw steel hammer",
"price": 8.9,
"starRating": 4.8,
"imageUrl": "assets/images/hammer.png"
},
In my component.ts clss I have within the ngOnInit function some logic that I tought would be able to subscribe to the service and add the data to the relevent data structures. Here is the component.ts class
import { Component, OnInit } from '@angular/core';
import { IProduct } from './product';
import { ServiceService } from '../../service/service.service';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
pageTitle = 'Product List';
imageWidth = 50;
imageMargin = 2;
showImage = false;
errorMessage: string;
_listFilter = '';
get listFilter(): string {
return this._listFilter;
}
set listFilter(value: string) {
this._listFilter = value;
this.filteredProducts = this.listFilter ? this.performFilter(this.listFilter) : this.products;
}
filteredProducts: IProduct[] = [];
products: IProduct[] = [];
constructor(private productService: ServiceService) {
}
onRatingClicked(message: string): void {
this.pageTitle = 'Product List: ' + message;
}
performFilter(filterBy: string): IProduct[] {
filterBy = filterBy.toLocaleLowerCase();
return this.products.filter((product: IProduct) =>
product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}
toggleImage(): void {
this.showImage = !this.showImage;
}
ngOnInit(): void {
this.productService.getProducts().subscribe({
next: products => {
this.products=products,
this.filteredProducts = this.products;
},
error: err => this.errorMessage =err
});
}
}
As you can see in the ngOnInit I subscribe to the observable and I also populate the products array with the product data from the observable but my products array is still empty and no data will show on the screen when bound to the .html class. Thanks for any help in advanced.
Upvotes: 1
Views: 356
Reputation: 73357
The issue is in the template, you have a *ngIf
:
<table class="table" *ngIf="Products && Products.length!=0">
Your component has no variable Products
, it is products
with lowercase P
. Also you don't actually need to check the length
, since if the array doesn't have items, angular won't even try to render the *ngFor
. But sure, always be on the safe side ;) But checking simply products.length
is enough, no need for !=0
.
Make following change on the *ngIf:
<table class="table" *ngIf="products && products.length">
Upvotes: 1