Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: "ctx.cart is undefined"

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

like image 785
Darshil Thakore Avatar asked May 09 '20 20:05

Darshil Thakore


3 Answers

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!

like image 79
T. Sunil Rao Avatar answered Oct 13 '22 00:10

T. Sunil Rao


I solved this problem with:

cart: Cart = {} as Cart;

instead of:

cart: Cart;
like image 35
Branimir Amidžić Avatar answered Oct 13 '22 00:10

Branimir Amidžić


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 ']
}
like image 25
Kacper Cieluch Avatar answered Oct 12 '22 23:10

Kacper Cieluch