AungHtetPaing__'s avatar

TypeError: this.products.splice is not a function

Hello, i'm doing laravel e-commerce project for the first time. And faced a error when product in cart is remove from cart. Splice() doesn't work.

here is my web.php

Route::get('/cart', 'CartController@index')->name('cart.index');
Route::post('/cart/{product}', 'CartController@store')->name('cart.store');
Route::delete('/cart/{product}', 'CartController@destroy')->name('cart.delete');

Route::get('/products', 'ProductController@index')->name('products.index');
Route::get('/products/{product:slug}', 'ProductController@show')->name('products.show');

Route::get('api/cart', 'Api\CartController@index');
Route::get('api/cart/clear', 'Api\CartController@clear')->name('cart.clear');

and CartController.php

public function index()
    {
        return Inertia::render('cart');
    }

    public function store(Product $product, Cart $cart)
    {
        $cart->add($product);
    }

    public function destroy(Product $product, Cart $cart)
    {
        $cart->remove($product);
    }

Cart.php

public function add($product)
    {
        $cart = session()->has($this->cartKey()) ? session($this->cartKey()): new Collection;
        if(isset($cart[$product->id]))
        {
            $cart[$product->id]->quantity++;
            session()->put($this->cartKey(), $cart);
            // return response('successfully added to your cart');
        }
        else {
            $cart[$product->id] = $product;
            $cart[$product->id]->quantity++;
            session()->put($this->cartKey(), $cart);
            // return response('item is already in your cart. Quantity has been updated!');
        }
    }

    public function remove($product)
    {
        session()->pull($this->cartKey() . ".{$product->id}");
    }

    protected function cartKey()
    {
        return "cart";
    }

and then i call cart from api to vue cart.vue

<template>
    <breeze-authenticated-layout>
        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                    <div class="p-6 bg-white border-b border-gray-200">
                        <!-- <button @click="clearCart">Delete cart</button> -->
                        <div v-if="products">
                            <div v-for="(product, index) in products" :key="product.id">
                                <h2>
                                    {{product.name}} - {{index}}
                                </h2>
                                <button @click="removeFromCart(index)">Delete</button>
                            </div>
                        </div>
                        <div v-else>
                            No Products in Session
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </breeze-authenticated-layout>
</template>

<script>
    import BreezeAuthenticatedLayout from '@/Layouts/Authenticated'
import axios from 'axios'
    
    export default {
        components: {
            BreezeAuthenticatedLayout,
        },

        data() {
            return {
                products: []
            }
        },

        mounted() {
            this.fetch()
        },

        methods: {
            fetch() {
                axios.get('/api/cart')
                    .then(response => {
                        this.products = response.data
                        console.log(response.data);
                    })
            },
            removeFromCart(id){
                // console.log(this.products);
                this.products.splice(id, 1);
                axios.delete(`/cart/${id}`);
            }
        }
    }
</script>

<style lang="scss" scoped>

</style>

After some attempts, i figured out that response from api is returning object. If it return array, splice is working fine. But i don't know how to change, object to array that is from api.

I'm sorry if i made mistake in asking question. This is my question for the first time.

0 likes
9 replies
SilenceBringer's avatar

@aung htet paing can you show 'Api\CartController@index' method?

i figured out that response from api is returning object

can you show the object?

1 like
AungHtetPaing__'s avatar

Of course i forgot to show api controller.

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;

class CartController extends Controller
{
    public function index()
    {
        return session("cart");
    }

    public function clear()
    {
        return session()->forget("cart");
    }
}
SilenceBringer's avatar

@aung htet paing please show this

public function index()
    {
dd(session("cart"));
        return session("cart");
    }
1 like
AungHtetPaing__'s avatar

@silencebringer here is api response

{
"1": {
"id": 1,
"category_id": 1,
"name": "animi",
"slug": "vel-vero-provident-at-quo",
"sku": "758",
"description": "Ab impedit aut debitis sint. Veniam iste reiciendis ut veritatis consequatur. Labore deserunt facilis distinctio. Amet illum porro eius libero.",
"price": 470.9,
"created_at": "2021-06-05T08:40:04.000000Z",
"updated_at": "2021-06-05T08:40:04.000000Z",
"quantity": 1
},
"2": {
"id": 2,
"category_id": 2,
"name": "modi",
"slug": "itaque-voluptas-voluptas-eligendi-sit-rem-voluptate-reiciendis",
"sku": "3776431",
"description": "Cum harum earum sit dignissimos sed. Aut ea sint excepturi eveniet.",
"price": 451,
"created_at": "2021-06-05T08:40:04.000000Z",
"updated_at": "2021-06-05T08:40:04.000000Z",
"quantity": 2
}
}
SilenceBringer's avatar

@aung htet paing this

{
"1": {

do you store product id as array keys? Do you need it?

otherwise, you can do

public function index()
    {
        return array_values(session("cart"));
    }

and it should fix the problem

1 like
AungHtetPaing__'s avatar

@silencebringer Yes i stored product id as array keys. I'm not sure it is really necessary but i used that key in cart.php to increase product quantity.

SilenceBringer's avatar
Level 55

@aung htet paing javascript do not support array with numeric keys not in default order (staring from 0, one by one), so, it's used as object.

Do not use product id as array key (you have it in item and can use it for seraching)

Or you can do the following, for example

in Api\CartController

public function index()
    {
        return array_values(session("cart"));
    }

in cart.vue

                            <div v-for="(product, index) in products" :key="product.id">
                                <h2>
                                    {{product.name}} - {{product.id}}
                                </h2>
                                <button @click="removeFromCart(index)">Delete</button>
                            </div>
// ...

            removeFromCart(index){
                let _this = this;
                let product = this.products[index]
                // console.log(this.products);
                this.products.splice(id, 1);
                axios.delete(`/cart/${product.id}`)
                  .then(response => {
                    _this.products.splice(index, 1)
                  });
            }
1 like
AungHtetPaing__'s avatar

@silencebringer thank you so much and sorry for my quick reply bcuz i copy paste your code and it showing error. After i checked condition in Api\CartController, it work.

public function index()
 {
        return session()->has("cart") ? array_values(session("cart")) : [];
 }

Please or to participate in this conversation.