Error del componente web Lightning: ['establecido' en el proxy: la captura devuelta falsa para la propiedad '0']

Aug 18 2020

Estoy tratando de construir un carrito donde agrego productos y luego puedo eliminarlos. Sin embargo, al eliminar, recibo el error ['set' on proxy: trap returned falsish for property '0'].

En mi componente ParentComponent, selecciono los productos y los agrego a una matriz cartItems. Para cada artículo del carrito, se crea una cartRowIteminstancia de un componente secundario llamado . Ver código a continuación:

parentComponent.html:

<template>
    <div class="slds-grid slds-gutters">
            <lightning-card class="slds-col slds-size_1-of-3" title="Product Search">
                <div class="slds-grid slds-gutters">
                    <div class="slds-col slds-size_2-of-3 slds-var-m-left_small">
                        <lightning-input type="text" placeholder="Search for a product" value={productSearchKey} onchange={handleSearchKeyChange}></lightning-input>
                    </div>
                    
                    <div class="slds-col slds-size_1-of-3">
                        <button class="slds-button slds-button_brand slds-button_stretch slds-var-m-right_small" onclick={doSearch}>Search</button>
                    </div>
                </div>

                <template if:true={products}>
                    <lightning-datatable
                        key-field="id"
                        data={products}
                        columns={columns}
                        onrowaction={addToCart}
                        hide-checkbox-column>
                    </lightning-datatable>
                </template>
                
            </lightning-card>

        <lightning-card class="slds-col slds-size_2-of-3" title="Product Cart">
            <template for:each={cartItems} for:item="item">
                <c-cart-row-item key={item.id} cart-item={item} cart-items={cartItems} oncartitemremove={handleRemove}></c-cart-row-item>
            </template>
        </lightning-card>
    </div>
</template>

parentComponent.js:

import { LightningElement, api, track } from 'lwc';
import findProducts from '@salesforce/apex/TechDocSelfServeController.findProducts';

const tableColumns = [{
    label: 'Product Code',
    fieldName: 'ProductCode',
    type: 'text',
    sortable: true
},
{
    label: 'Product Name',
    fieldName: 'Name',
    type: 'text',
    sortable: 'true'
},
{
    label: 'Add to Cart',
    type: 'button-icon',
    
    typeAttributes: 
    {
        iconName: 'utility:add',
        name: 'addToCart',
        title: 'addToCart',
        disabled: false,
        alternativeText: 'Add to Cart',
    }
}];

export default class TechDocSelfServe extends LightningElement {
    products; 
    @api cartItems = [];
    columns = tableColumns;
    productSearchKey = '';
    error;
    
    doSearch() {
        let productSearchKey = this.productSearchKey;
        findProducts({ productSearchKey })
            .then((result) => {
                this.products = result;
                this.error = undefined;
            })
            .catch((error) => {
                this.error = error;
                this.products = undefined;
            });
    }

    addToCart(event) {
        const row = event.detail.row;
        this.cartItems = [...this.cartItems, row];
    
        const selectedEvent = new CustomEvent("cartitemadd", {
            detail: this.cartItems
        });

        console.log('cartItems on add -> ' + JSON.stringify(this.cartItems, null, 4));

        this.dispatchEvent(selectedEvent);
    }

    handleSearchKeyChange(event) {
        this.productSearchKey = event.target.value;
    }

    handleRemove(event) {
        this.cartItems = event.detail
    }
}

cartRowItem.html:

<template>
    <template if:true={displayRow}>
        <div class="slds-var-m-around_xx-small slds-box">
            <lightning-card>
                <div class="slds-text-heading_large slds-text-align_center "><u>{cartItem.Name}</u></div>
                    <lightning-button variant="destructive" label="Remove Item" title="RemoveItem" onclick={handleRemove} value={cartItem} class="slds-align_absolute-center"></lightning-button>
            </lightning-card>    
        </div>
    </template>
</template>

cartRowItem.js (actualizado según el comentario de Rahul):

import { LightningElement, api } from 'lwc';

export default class CartRowItem extends LightningElement {
    @api cartItem;
    _cartItems;
    displayRow = true;

    @api get cartItems() {
        return this._cartItems;
    }

    set cartItems(value) {
        this._cartItems = value;
    }

    handleRemove(event) {
        console.log('Should remove here.')
        var array = this._cartItems;
        var key = event.target.value.Id;
        var index = array.findIndex(function(item, i) {
            return item.Id === key
        });

        array.splice(index, 1);
        this._cartItems = array;

        console.log('cartItems after remove -> ' + JSON.stringify(this._cartItems, null, 4));
        
        const selectedEvent = new CustomEvent("cartitemremove", {
            detail: this._cartItems
        });

        this.dispatchEvent(selectedEvent);
        this.displayRow = false;
    }
}

Al presionar el botón Eliminar en cartRowItem, recibiré el error ['set' on proxy: trap returned falsish for property '0']con el número al final cambiando según el elemento de la matriz que estoy tratando de eliminar.

Respuestas

2 rahulgawale Aug 18 2020 at 21:35

La propiedad establecida por el producto principal es inmutable, lo que significa que no se puede modificar. Necesita usar el setter getter para la propiedad pública.

_cartItems;
...

@api
get cartItems(){
    return this._cartItems;
}

set cartItems(value){
    this._cartItems = JSON.parse(JSON.stringify(value));
}

Tenga en cuenta que he creado una nueva propiedad privada con un nombre diferente, es decir _cartItems.

Ahora puede realizar todas las operaciones y actualizar el _cartItems. Para enviar datos actualizados al padre, debe enviar un evento personalizado del hijo.