0

Hi I am new to both coding and LWC, just trying to create a simple component that displays a table of order items in two columns. I want to display only first three items then display a "Show More" button which when clicked should display the rest. Before adding this logic component was displaying correctly but now it says: Error during LWC component constructor phase: [items is not defined] and also "Error during LWC component constructor phase: [Cannot read properties of undefined (reading 'length')]"

Here are my JS and html code. Any help and hints would be highly appreciated as I am really trying to understand and learn LWC. Few comments to avoid confusion, I am using custom labels from salesforce org so its not the problem with labels, and I am using @api for items because in real the value should come from a parent component.

JS

import { LightningElement, api} from 'lwc';
import  DeliveryProductDetails from '@salesforce/label/c.DeliveryProductDetails';
import  DeliveryOrderedItems from '@salesforce/label/c.DeliveryOrderedItems';
import  DeliveryItemNumber from '@salesforce/label/c.DeliveryItemNumber';
export default class ProductInfoParent extends LightningElement {
    @api items=[{
        articleNo: "A-B2-U",
        articleImageUrl: "http://cdn.parcellab.com/img/sales-cannon/parcellab-bag.jpg",
        quantity: 1,
        sku: "A-B2-U",
        product_name: "parcelLab Tote Bag"
    },
    {
        articleNo: "A-C1-L",
        articleImageUrl: "http://cdn.parcellab.com/img/sales-cannon/parcellab-cap.jpg",
        quantity: 2,
        sku: "A-C1-L",
        product_name: "parcelLab Branded Cap"
    },
    {
        articleNo: "A-B2-T",
        articleImageUrl: "http://cdn.parcellab.com/img/sales-cannon/parcellab-bag.jpg",
        quantity: 1,
        sku: "A-B2-T",
        product_name: "parcelLab Tote Bag"
    },
    {
        articleNo: "A-C1-D",
        articleImageUrl: "http://cdn.parcellab.com/img/sales-cannon/parcellab-cap.jpg",
        quantity: 2,
        sku: "A-C1-D",
        product_name: "parcelLab Branded Cap"
    }]; 

    @api showMore = (this.items.length > 3) ? false : true;

    label = {
        DeliveryProductDetails,
        DeliveryOrderedItems,
        DeliveryItemNumber,
        //ShowMore
    }; 

    
    connectedCallback(){
        this.firstThree = showThree(this.items);
        this.showMore = showMore;
    }
    
    
    showThree(items){
        let firstThree = [];
        for(let i=0 ; i <3 ; i++  ){
            firstThree.push(items[i]);
        }
        return firstThree;
    }
    
    
    showMore(items){
        let showMoreItems = [];
        if(items.length>3){
            for(let i=3 ; i <items.length ; i++  ){
                showMoreItems.push(items[i]);
            }
            return showMoreItems;
        }
        else {
            return showMoreItems=[null];
        }
    }
    
    handleClick(){
        this.showMore = true;
        showMore(this.items);
    }
    
}

 

HTML

<template>
  <h1 class="slds-text-heading_small slds-m-bottom_small">
      <strong>{label.DeliveryProductDetails}</strong>
  </h1>
  <div>
      <table>
          <tr class="slds-m-bottom_small">
              <th class="slds-text-heading_small" width="10px">
                  <strong>{label.DeliveryOrderedItems} </strong>
              </th>
              <th class="slds-text-heading_small" width="30px">
                  <strong>{label.DeliveryItemNumber}</strong>
              </th>
          </tr>
          <template class="slds-text-heading_small" for:each={firstThree} for:item="item">
              <tr key={item.articleNo}>
                  <td>{item.quantity} x {item.product_name}</td>
                  <td>{item.articleNo}</td>
              </tr>
          </template>
          <template if:false={showMore}>
              <lightning-button variant="brand" label="Show More" title="ShowMore" onclick={handleClick}
                  class="slds-m-right_small">
              </lightning-button>
          </template>
          <template class="slds-text-heading_small" if:true={showMore} for:each={showMoreItems} for:item="item">
              <tr key={item.articleNo}>
                  <td>{item.quantity} x {item.product_name}</td>
                  <td>{item.articleNo}</td>
              </tr>
          </template>
      </table>
  </div>
</template>

2 Answers 2

0

You have a this missing here:

firstThree.push(items);

and here:

showMore = (items.length > 3) ? false : true;

Having to explicitly include this. is troublesome if you are used to languages that don't always require it.

Do also evaluate using the lighting-datatable component for future tables. It has useful stuff built in including a "load more" mechanism, and its limitations keep you from straying too far from what SLDS ties down.

1
  • 1
    There, uhh, more, than just that which is wrong (pun intended), such as this.showMore = true, duplicate names, etc.
    – sfdcfox
    Commented Dec 11, 2021 at 15:41
0

You can't have a property and a function with the name name in the same class:

showMore = items.length > 3 ? false : true;

...

  showMore(items) {
    let showMoreItems = [];
    if (items.length > 3) {
      for (let i = 3; i < items.length; i++) {
        showMoreItems.push(items);
      }
      return showMoreItems;
    } else {
      return showMoreItems = [null];
    }
  }

You must always refer to class elements with this, both for functions and properties.

showMore(this.items);

Would be:

this.showMore(this.items);

Which, coincidentally, makes some of your code nonsensical:

this.showMore = showMore;

Should be:

this.showMore = this.showMore;

Which obviously has no effect.


There's several inefficiencies in your code, such as using Array.prototype.push when Array.prototype.slice would serve equally well:

showThree(items) {
  return items.slice(0, 3) // returns first 3 items
}

Some of the rest of the code makes no apparent sense, such as:

  return showMoreItems = [null];

You're trying to return a list of one element that is a null value?


You have to declare a property to use it. The following is problematic:

this.firstThree = showThree(this.items);

Because firstThree isn't declared at the class level.


Aside from that, all of this should be handled through a lightning-datatable, unless you've got some reason why you're avoiding this. It's usually sufficient for most use cases.


I'll stop here for now, but suffice to say, you'll want to review what I've written so far, and the lightning-datatable documentation, then post a revised version so we can help you further.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .