Angular with PHP & MYSQL to display products list & paging

In the third part of Angular tutorials, you learn to create Angular component and service to display products list from API endpoints, filter products by name and do pagination.
Execute command below to create produce service in services folder. The product service is used to count products with search text and retrieve product list with search text and  a range of specified start and limit parameters from API endpoints. The APIs requires a token to authenticate. So, you need to add the token to the request headers.

ang14-client>ng generate service services/product

services/product.service.ts
import { Injectable } from '@angular/core';
import { HttpClient} from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { HttpHeaders } from '@angular/common/http';
import { AuthService } from '../services/auth.service';
import {api_url_root} from "../app.constants";
import {Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  constructor(
    private router: Router,
    private http:HttpClient, 
    private authservice: AuthService
   ) 
   {
     this.token=this.authservice.getToken();   
   }
  
  public products!:any;
 
  token:any;

  baseUrl:string=api_url_root+"api/";
 

  public getDataCount(search: any): Observable<any>{
   let headers = new HttpHeaders()
    .set('Content-Type', 'application/json')
    .set('Authorization', this.token || '{}');
    let url=search?this.baseUrl+"products/count/"+search:this.baseUrl+"products/count";
    return this.http.get(url,{'headers':headers})
    .pipe(
      map((response) => {
        
        let jsonObj=JSON.parse(JSON.stringify(response));
        console.log("data=",jsonObj.data);
        return(jsonObj.data);
       
      
     }),
      catchError((err) => {
        console.error(err);
        throw err;
      }
      )
  
    )

  }

  public getDataLimit(search: string, start:number,limit:number): Observable<any>{
   
    let headers = new HttpHeaders()
    .set('Content-Type', 'application/json')
    .set('Authorization', this.token || '{}');
    
    let url=search?this.baseUrl+"products/"+start+"/"+limit+"/"+search:
    this.baseUrl+"products/"+start+"/"+limit;
  
    return this.http.get(url,{'headers':headers})
    .pipe(
      map((response) => {
        
        console.log("products list=",response);
        let jsonObj=JSON.parse(JSON.stringify(response));
        
        return(jsonObj);
      
      
     }),
      catchError((err) => {
        console.error(err);
        throw err;
      }
      )
  
    )

  }

  

}

Run the following command to create product component.

ang14-client>ng generate component product

product/product.component.ts
import { Component, OnInit } from '@angular/core';
import { ProductService } from '../services/product.service';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-product',
  templateUrl: './product.component.html',
  styleUrls: ['./product.component.css'],
})
export class ProductComponent implements OnInit {
  products?:any=[];
  constructor(private authService: AuthService,private route: ActivatedRoute,private router: Router,private productService:ProductService,private http: HttpClient) { }
  
  start_: number = 0;
  limit_: number = 3;
  total_rows: number = 0;
prev_total_rows=0;
 
  public getProductsCount() {
     
    this.products=this.productService!.getDataCount(this.search)
    .subscribe({
      next:(response) => {                          
      
        this.total_rows=response;
        this.prev_total_rows=this.total_rows;
             
      },
      error: (e) => {                             
        console.error('Request failed with error'+e)
          },
      complete: () => {                                   
        console.error('Request completed')     
        
        }
      });
    
    
  }

  public getProductsLimit() {

    this.products=this.productService!.getDataLimit(this.search,this.start_,this.limit_)
    .subscribe(
      {
        next: (response) => {
         
          if(response.status===200){ 
            this.products = response.data; 
            if(this.search!='') this.total_rows=this.products.length; // reset total_rows to number of rows matched
            else this.total_rows=this.prev_total_rows; // restore total_rows
          }
          else  if(response.status===401){ 
            this.router.navigateByUrl("/login"); 
          }
        },
        error: (e) => {
          console.error('Request failed with error'+e)
        },
        complete: () => console.info('request complete') 
     }
    
      );
    
    
  }  



  ngOnInit(): void {
    
   
    if(this.authService.isLoggedin()){
      
      this.getProductsLimit();
      this.getProductsCount();
      
    }
    else{
      this.router.navigateByUrl("/login"); 
    }
  }
  dataset?:any=[];
  search: string = "";

  public searchByName(){
    this.start_=0; // reset start
    this.getProductsLimit();
    
  }

  public moveNext = () =>{
      if(this.total_rows-this.start_>=this.limit_  && this.total_rows>this.limit_)  
      
      {
        this.start_+=this.limit_;
        this.getProductsLimit();
      }
  }
  public movePrev = () =>{
    if(this.start_-this.limit_>=0 && this.total_rows>this.limit_) 
    {
      this.start_-=this.limit_;
      this.getProductsLimit();
    }
  }

  public canmoveNext(){
      return (this.total_rows-this.start_>this.limit_  && this.total_rows>this.limit_) ;
  }
  public canmovePrev(){
    return (this.start_-this.limit_>=0 && this.total_rows>this.limit_) 
}

 

}

product/produtct.component.html

<div class="product-list">
<div class="form-group row">
    <div class="col-sm-5"> 
    <input type="text" [(ngModel)]="search" placeholder="search" class="form-control" name="search" />
    </div><div class="col-sm-2"> 
    <button class="btn btn-primary" type="button" (click)="searchByName()"><span class="material-icons-outlined">search</span></button>
     </div>
    <div style="float: right; margin-right: 20px;">
    <button class="btn btn-primary" type="button" (click)="addProduct()"><span class="material-icons-outlined">add</span></button>
    </div>  
</div>

<div><h2><span class="material-icons-outlined plisth">view_list</span>  Products List</h2></div>
     <div class='table-responsive'>
            <table class='table'>
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Name</th>
                        <th>Description</th>
                        <th>Slug</th>
                        <th>Price</th>
                        <th>Category</th>
                        <th>Sub Category</th>
                        <th>Image</th>
                    </tr>
                </thead>
                <tbody>
                    <tr *ngFor="let product of products;">
                        <td>{{product.id}}</td>
                        <td>{{product.name}}</td>
                        <td>{{product.description}}</td>
                        <td>{{product.slug}}</td>
                        <td>{{product.price}}</td>
                      
                        <td>{{product.category}}</td>
                        <td>{{product.subcategory}}</td>
                        <td><img width="50" height="50" src="http://localhost:81/angphp_demo/download.php?fname={{product.thumbnail}}" /></td>
                      

                        <td><a [routerLink]="['/product',product.id]"><span class="material-icons-outlined">edit_note</span></a></td>
                        <td><a [routerLink]="['/products',product.id]"><span class="material-icons-outlined acdelete">delete_forever</span></a></td>
                    </tr>
                </tbody>
            </table>
            <span style="margin-right:  10px;" *ngIf="canmoveNext()">
            <button class="btn btn-primary" type="button" (click)="moveNext()">></button>
            </span>
            <span *ngIf="canmovePrev()">
            <button class="btn btn-primary" type="button" (click)="movePrev()"><</button>
            </span>       
        </div>
    </div>

product/product.component.css

@import 'material-icons/iconfont/outlined.css';
.material-icons-outlined{
    display: inline-flex;
    vertical-align: middle;

}
.row{
    padding-left: 20% !important;
}
.plisth{
    font-size: 40px;
}
.acdelete{
    color:red;
}
.product-list{
    padding-left: 15%;
}


Finally, add products route to app-routing.module.ts file.
 
import { ProductComponent } from './product/product.component';
const routes: Routes = [

  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: 'products', component: ProductComponent },

];

Save the project. Log into the app, you should see a list of products, be able to search products by name, and do pagination when the number of products are greater than 3.




Angular Tutorial: Upload Form with Files

Comments

Popular posts from this blog

Angular Upload Form Data & Files

PHP Mysql Database Migration Using Phinx