I'm working on a simple shopping MEAN stack application. On the header component I have a cart with badge that shows number of elements on the user's cart,when I click on add to cart button (which is situated on my products component), the product is added normally but the number of elements on cart only updates when I refresh the page. This is my header template code :
<div class="input-group input-group-sm">
<div class="input-group-append" *ngFor="let p of panier">
</div>
<a class="btn btn-success btn-sm ml-3" *ngIf="isConnected" routerLink="/panier">
<!-- <a class="btn btn-success btn-sm ml-3" *ngIf="!isConnected" routerLink="/"></a> -->
<i class="fa fa-shopping-cart"></i> Cart
<span class="badge badge-light">{{getSize()}}</span>
</a>
</div>
This is my header component code:
import { Component, OnInit, Input } from '@angular/core';
import { AuthentificationService } from '../authentification.service';
import { ProduitsService } from '../produits.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
user;
isConnected = false;
private panier: [];
size=0;
constructor(private AuthService : AuthentificationService,
private produitsService: ProduitsService) { }
setSize(quantite){
this.size+=quantite;
}
getSize(){
console.log(this.panier.length);
return this.size;
}
ngOnInit() {
this.AuthService.getUser().subscribe(data =>{
this.AuthService.getUser().subscribe(data =>{
console.log(data);
this.user = data;
if ( this.user ){Â this.isConnected = true;}
else {Â this.isConnected = false;}
console.log("est connecté : " + this.isConnected );
this.produitsService.getproduitsPanier(this.user).subscribe(data => {
// console.log("received : " + JSON.stringify(data));
this.panier = data;
if (this.panier) //dans le cas où le panier n'est pas encore initialisé
this.size = this.panier.length;
console.log("produits : " + this.panier);
});
});
});
}
}
And this is my product component code:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ProduitsService } from '../produits.service';
import { AuthentificationService } from '../authentification.service';
import { Observable } from 'rxjs';
import {HomeComponent} from '../home/home.component'
@Component({
selector: 'app-produits',
templateUrl: './produits.component.html',
styleUrls: ['./produits.component.css']
})
export class ProduitsComponent implements OnInit {
private produits: Object[] = new Array();
user;
isConnected = false;
produitAEnvoyer = {
"email":"",
"img" :"",
"nom" :"",
"marque" : "",
"prix" : "",
"quantite" :""
};
constructor(
private route: ActivatedRoute,
private produitsService: ProduitsService,
private AuthService : AuthentificationService,
private HomeComponent : HomeComponent) {
}
ajouterAuPanier(img, nom, marque, prix){
this.produitAEnvoyer.email = this.user;
this.produitAEnvoyer.img = img;
this.produitAEnvoyer.nom = nom;
this.produitAEnvoyer.marque = marque;
this.produitAEnvoyer.prix = prix;
console.log(this.produitAEnvoyer);
this.produitsService.ajouterAuPanier(this.produitAEnvoyer).subscribe(data => {
console.log(data);
})
}
updateQuantite(value){
this.produitAEnvoyer["quantite"] = value;
console.log("quantite :"+this.produitAEnvoyer.quantite);
}
ngOnInit() {
this.produitsService.getProduits().subscribe(produits =>{
this.produits = produits;
for (const p of this.produits) {
this.produits.sort();
console.log(JSON.stringify(p));
}
});
this.AuthService.getUser().subscribe(data =>{
console.log(data);
this.user = data;
if ( this.user ){Â this.isConnected = true;}
else {Â this.isConnected = false;}
console.log("est connecte : " + this.isConnected+" email :"+this.user);
});
}
}
Edit 1: This is also my product template :
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css">
<div class="container">
<br> <b><h2 class="text-center"> Catalog of All Our Products ! </h2></b>
<hr>
<br><br>
<div class="card" >
<table class="table table-hover shopping-cart-wrap">
<thead class="text-muted">
<tr>
<th scope="col">Product</th>
<th scope="col" width="120">Brand</th>
<th scope="col" width="120">Price</th>
<th scope="col" width="120">Quantity</th>
<th scope="col" width="200" class="text-right">Action</th>
</tr>
</thead>
<tbody *ngFor="let produit of produits">
<tr>
<td>
<figure class="media" >
<div class="img-wrap"><img src={{produit.img}} class="img-thumbnail img-sm"></div>
<figcaption class="media-body">
<h6 class="title text-truncate"> {{produit.nom}} </h6>
</figcaption>
</figure>
<td>
<div class="price-wrap">
<var class="price"> {{produit.marque}} </var>
</div> <!-- brand-wrap .// -->
</td>
<td>
<div class="price-wrap">
<var class="price">USD {{produit.prix}} $</var>
<small class="text-muted">(For 1 quantity)</small>
</div> <!-- price-wrap .// -->
</td>
<td>
<div class="price-wrap">
<input class="form-control" type="number" required (click)="updateQuantite($event.target.value)" min="1" max="20"/>
</div> <!-- quantity-wrap .// -->
</td>
<td class="text-right" >
<a title="" (click)= "ajouterAuPanier(produit.img, produit.nom, produit.marque, produit.prix)" class="btn btn-outline-success" data-toggle="tooltip" data-original-title="Save to Wishlist" > <i class="fa fa-heart" ></i> Add to cart</a>
</td>
</tr>
<tr>
</tbody>
</table>
</div> <!-- card.// -->
</div>
<!--container end.//-->
Using Service
and Rxjs subject
can solve your problem.
When add
or remove
button is clicked, the header must be informed that some event occurred and updated the latest value. For that Service
can be used as the communication channel.
Note: @input
and @output
can be used only if components are in the parent-child relationship. So for this case using Service is the best option.
To update the value in the header component Observable
can be used.
header.component.ts
export class HeaderComponent {
...
ngOnInit() {
this.appService.getCount().subscribe(count => {
this.totalItem = count
}
);
}
...
}
appService
export class AppService {
count = 0;
simpleObservable = new Subject();
simpleObservable$ = this.simpleObservable.asObservable();
constructor() { }
addCount() {
this.count+=1;
this.simpleObservable.next(this.count)
}
removeCount() {
if (this.count > 0) { this.count-=1 };
this.simpleObservable.next(this.count)
}
getCount(){
return this.simpleObservable$;
}
}