Reputation: 4684
I am working on an e-commerce app who's front-end is made in Angular 13.
I use a CartService
service to add products to the cart (app\services\cart.service.ts
):
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { Product } from '../models/product';
@Injectable({
providedIn: 'root'
})
export class CartService {
subject = new Subject();
product: Product | undefined;
constructor() { }
sendProductTocart(product: Product) {
this.subject.next(product);
}
}
In app\components\product-item\product-item.component.ts
I have:
import { Component, OnInit, InputDecorator, Input } from '@angular/core';
import { Product } from '../../models/product';
import { CartService } from '../../services/cart.service';
@Component({
selector: 'app-product-item',
templateUrl: './product-item.component.html',
styleUrls: ['./product-item.component.css']
})
export class ProductItemComponent implements OnInit {
@Input() product!: Product;
@Input() handleAddToCart!: (args: any) => void;
constructor(private cartService: CartService) { }
addToCart(product: Product) {
console.log(this.cartService.product);
}
ngOnInit(): void {
}
}
In app\components\add-to-cart\add-to-cart.component.ts
I have:
import { Component, OnInit, InputDecorator, Input } from '@angular/core';
import { Product } from '../../models/product';
@Component({
selector: 'app-add-to-cart',
templateUrl: './add-to-cart.component.html',
styleUrls: ['./add-to-cart.component.css']
})
export class AddToCartComponent implements OnInit {
@Input() product!: Product;
@Input() handleAddToCart!: (args: any) => void;
constructor() { }
ngOnInit(): void {
}
}
In app\components\add-to-cart\add-to-cart.component.html
:
<button class="btn btn-sm btn-success w-100" (click)="handleAddToCart(product)">Add</button>
The goal is to add products to the top-cart component (app\components\top-cart\top-cart.component.ts
), more exactly, to the cartItems
array:
import { Component, OnInit } from '@angular/core';
@Component({
selector: '.app-top-cart',
templateUrl: './top-cart.component.html',
styleUrls: ['./top-cart.component.css']
})
export class TopCartComponent implements OnInit {
cartItems: any = [
];
constructor() { }
totalPrice: number = 0;
doTotalPrice() {
let total = 0;
this.cartItems.forEach((item: { price: number, quantity: number }) => {
item.quantity = 1;
total += item.price * item.quantity
});
this.totalPrice = total;
}
ngOnInit(): void {
this.doTotalPrice();
}
}
See Stackblitz demo here.
For a reason I have not been able to find out, when I click the "Add to cart" button in the product list, I get this error in the Ghrome console:
Cannot read properties of undefined
Upvotes: 1
Views: 454
Reputation: 8042
You're doing this, passing function down to child
<div class="card-footerer p-1">
<app-add-to-cart [handleAddToCart]="addToCart"></app-add-to-cart>
</div>
But in your child component
@Component({
selector: 'app-add-to-cart',
templateUrl: './add-to-cart.component.html',
styleUrls: ['./add-to-cart.component.css']
})
export class AddToCartComponent implements OnInit {
@Input() product!: Product;
@Input() handleAddToCart!: (args: any) => void;
constructor() { }
ngOnInit(): void {
}
}
the service cartService
is not injected into this child component. this
is not passed down but is referring now to AddToCartComponent
. And this.cartService
is not defined. So it's throwing error
ERROR Error: this.cartService is undefined
(in firefox)
Use an event emitter to pass the data up and handle event in parent.
export class AddToCartComponent {
@Input() product!: Product;
@Output() productAdded: EventEmitter<Product> = new EventEmitter();
constructor() { }
ngOnInit(): void {
}
handleAddToCart(product: Product) {
this.productAdded.emit(product)
}
}
<app-add-to-cart (productAdded)="addToCart($event)"></app-add-to-cart>
Upvotes: 1
Reputation: 1040
You need to add the product:
now:
<div class="card-footerer p-1">
<app-add-to-cart [handleAddToCart]="addToCart"></app-add-to-cart>
</div>
should be:
<div class="card-footerer p-1">
<app-add-to-cart [handleAddToCart]="addToCart"
[product]="product"></app-add-to-cart>
</div>
Upvotes: 1