Reputation: 85
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.//-->
Upvotes: 1
Views: 1733
Reputation: 753
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$;
}
}
Upvotes: 2
Reputation: 1434
You could set up the communication between parent and child component using @Input()
, @Output()
and EventEmitter
but as you already have a ProduitService
you could use it to share data. In your case the total number of items.
Set a BehaviorSubject
in your ProduitService:
total = new BehaviorSubject<number>(0);
setTotalItems(value: number) {
this.total.next(value);
}
Then in your ProduitsComponent you can set the value:
this.produitService.setTotalItems(value);
For a somewhat related case see this: How to communicate with other component in Angular 8 to Add Total
And it's related Stackblitz I made: https://stackblitz.com/edit/angular-bqxex9
The you can find a simple implementation of a communication between components using a shared service.
Upvotes: 0