I'm working on pizza ordering app, and currently I'm trying to implement Cart.
I have a cart for every user, and each cart contains following details: cart.ts
import { CartItem } from './cartitem';
export class Cart {
id: string;
user: string;
cartitems: CartItem[];
grand_total: number;
}
User can add items from the menu, which will become my cart items: cartitem.ts
import { Topping } from './topping';
export class CartItem {
id: string;
name: string;
baseprice: number;
toppings: Topping[];
extraprice: number;
quantity= 1;
total: number;
}
So on adding an item to the cart, I'm making a PUT request on the API endpoint on the user cart, to put the cart item, and in response, I'm returning the cart contents from there.
Here's how my cart.component.ts looks:
import { Component, OnInit, ViewChild, Inject, Injector } from '@angular/core';
import { CartItem } from '../shared/cartitem';
import { ActivatedRoute } from '@angular/router';
import { CartService } from '../services/cart.service';
import { map, catchError } from 'rxjs/operators';
import { Cart } from '../shared/cart';
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.scss']
})
export class CartComponent implements OnInit {
cart: Cart;
// cartitems: CartItem[];
constructor(
private route: ActivatedRoute,
private cartService: CartService,
@Inject('BaseURL')public BaseURL) { }
ngOnInit(): void {
this.updateCart();
}
updateCart() {
this.cartService.mysubject.subscribe((value) => {
console.log(value);
this.cartService.getItems().subscribe(response => {
console.log("Response in cart comp:", response);
let cartContent = new Cart();
cartContent.cartitems = response['cartitems'];
cartContent.id = response['id'];
cartContent.grand_total = response['grand_total'];
cartContent.user = response['user'];
this.cart = cartContent;
console.log("Cart is:", this.cart);
});
});
}
}
Now issue here is that I'm not able to bind the data on cart.component.html side with 'cart', it generates this error- ERROR TypeError: "ctx.cart is undefined".
I'm clueless on how to fix this.
Edit: Here is the cart.component.html:
<h2>Cart</h2>
<div>{{cart.user}}</div>
<mat-list dense>
<mat-list-item *ngFor="let cartitem of cart.cartitems">
<h2 matLine>Item: {{cartitem.name}}</h2>
<p matLine>Base Price: ${{cartitem.baseprice}}</p>
<p matLine [hidden]="cartitem.toppings == []">Extra Toppings:
<mat-list matLine>
<mat-list-item matLine *ngFor="let topping of cartitem.toppings">
<h4 matLine>{{topping.name}} : + ${{topping.rate}}</h4>
</mat-list-item>
</mat-list>
</p>
<button mat-mini-fab color="primary"><i class="fa fa-minus-circle"></i></button><div></div><button mat-mini-fab color="primary"><i class="fa fa-plus-circle"></i></button>
</mat-list-item>
</mat-list>
<div [hidden]="!cart.cartitems"><h2>Subtotal: ${{cart.grand_total}}</h2></div>
<div [hidden]="cart.cartitems">
<p> Your Cart is Empty!</p>
</div>
and error log:
ERROR TypeError: "ctx.cart is undefined"
CartComponent_Template cart.component.html:2
Angular 26
executeTemplate
refreshView
refreshComponent
refreshChildComponents
refreshView
refreshComponent
refreshChildComponents
refreshView
refreshDynamicEmbeddedViews
refreshView
refreshComponent
refreshChildComponents
refreshView
renderComponentOrTemplate
tickRootContext
detectChangesInRootView
detectChanges
tick
next
invoke
onInvoke
invoke
run
run
next
schedulerFn
RxJS 5
Angular 8
core.js:6185:19
The HTML added shows the error in line 2 of HTML
<div>{{cart.user}}</div>
cart
is defined as in your TS file
cart: Cart;
The interpolated value cart.user
is not available as cart
itself is undefined at time of init. cart
is populated later when subscription resolves.
A quick work-around maybe to wrap this in an ng-container
and use *ngIf
on it.
<ng-container *ngIf="cart">
<h2...
...
</div>
</ng-container>
This will not display anything till the cart
is resolved.
However, in terms of better code quality, replace all your interpolations with getters in the TS
get cartUser() { return (cart && cart.user) ? cart.user : null }
Now your HTML will be like
<div>{{cartUser}}</div>
Same way, you will get error for cart.cartitems
. Use this getter
get cartCartitems() { return (cart && cart.cartitems) ? cart.cartitems : [] }
and replace all instances of cart.cartitems
with cartCartitems
in your HTML
Hope it helps!
I solved this problem with:
cart: Cart = {} as Cart;
instead of:
cart: Cart;
We don't have html context where we can see how you bind ctx
, but I guess it's caused because ctx
does not exist in your component and you're trying bind to it. This kind of error is thrown when you're accesing object property which is undefined.
For example:
let someIncorrectObject = undefined;
someIncorrectObject.someValue // ERROR TypeError: "someIncorrectObject.someValue is undefined".
Try binding values in html like this <div> {{ cart.id }}</div>
and it should work.
as a side note it would be much easier and better in terms of code quality if you would do it like this:
// now we dont need to explicitly instantiate new class
export interface Cart {
id: string;
user: string;
cartitems: CartItem[];
grand_total: number;
}
and in code do the following
this.cart = {
cartitems: response['cartitems'],
id: response['id'],
grand_total : response['grand_total'],
user : response['user ']
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With