Search code examples
javascriptclassshopifycustom-elementreferenceerror

Why is a declared javascript class I'm extending return console error: 'Uncaught ReferenceError: [superclass] is not defined'?


I'm trying to extend a class to take advantage of its quickAddItem methods. However, when I go to extend it into a new class, the console error Uncaught ReferenceError: QuickaddDrawer is not defined. Here is the code, and below I'll outline what I've already tried.

if(!customElements.get("quickadd-drawer")) {
  customElements.define("quickadd-drawer", class QuickaddDrawer extends HTMLElement {
    constructor() {
      super();

      this.sidecart = document.querySelector("side-cart");
    }

    connectedCallback() {
      this.atcBtn = this.querySelector(".atc-btn");
      this.atcBtn.addEventListener("click", this.toggleDrawer.bind(this));

      this.quickaddBtns = this.querySelectorAll(".quickadd-btn:not([disabled])");
      this.quickaddBtns.forEach(btn => btn.addEventListener("click", this.quickAddItem.bind(this)));
    }

    toggleDrawer() {
      this.atcBtn.classList.toggle("drawer--open");
    }

    quickAddItem(event) {
      const btn = event.target;
      const variantId = btn.dataset.quickAdd;
      console.log("button", btn, variantId);
      this.sidecart.addToCart(variantId);
    }
  });
}

class CardBubbles extends QuickaddDrawer {
  constructor() {
    super();
    this.productCard = this.closest('product-card');
    this.bubbles = this.querySelectorAll('li>a');
    this.quickaddListings = this.productCard.querySelector('.quickadd-btn__listing');
    this.slideAnchors = this.productCard.querySelectorAll('.product-card__wrapper .swiper-slide a');
    this.initBubbles();
  }

  initBubbles() {
    this.bubbles.forEach(item=> item.addEventListener('click', this.handleClick.bind(this)));
  }

  handleClick(event) {
    event.preventDefault();
    this.updateImageLink(event);
    // update available size buttons
    this.checkForData(event);
    // update add to cart button
    // update featured images
    // update circled swatch
  }

  updateImageLink(event) {
    const variantLink = new URL(event.target.href);
    this.slideAnchors.forEach(el=>{
      el.href = el.href.replace(/\/products\/(.*)/, variantLink.pathname);
    });
  }

  checkForData(event) {
    // update with available sizes
    let targetVariantJSON = document.querySelector(`product-card script[data-product-id="${event.target.dataset.productId}"]`);
    if (targetVariantJSON) {
      const data = JSON.parse(targetVariantJSON.textContent);
      this.updateQuickaddBtns(data);
      this.updateImages(data);
    } else {
      console.log('fetching JSON');
      fetch(`${event.target.href}.js`)
      .then( res => res.json())
      .then( data => this.updateQuickaddBtns(data));
    }
    // bind to quickadd functions
  }

  updateQuickaddBtns(data) {
    console.log(data);
    console.log(data.available);
    let availableSizes=[];
    this.quickaddListings.innerHTML = '';
    data.variants.forEach(item=>{
      console.log(`Variant: ${item.id}, size ${item.option1} is available: ${item.available}`);
      const newButton = document.createElement('a');
      newButton.classList.add('quickadd-btn');
      newButton.dataset.quickAdd = item.id;
      newButton.innerText = item.option1;
      if (item.available == false) {
        console.log('is false, will attempt to add disabled attribute now');
        newButton.setAttribute("disabled", "");
      }
      this.quickaddListings.append(newButton);
    });
    console.log(availableSizes);
  }
  updateImages(data) {
    //update images with data
  }
}

customElements.define('card-bubbles', CardBubbles);

The new class and its element CardBubbles work fine when I extend an HTMLElement, though I'm at the point where I need to invoke the QuickaddDrawer methods, so I'd like to get this working instead of duplicating the code if possible.

I've tried different syntaxes for declaring the QuickaddButton class. I've tried removing the conditional statement in case the class definition was scoped within it, as I'd seen that as how extensions were working elsewhere in the code. I've also tried declaring the CardBubbles class and its element within the if(!customElements.get("quickadd-drawer")) { statement to further test if it was a scoping issue, but I get the same ReferenceError each time.

Big Question: Why is this class still not defined? How can I fix it?

Bonus questions: The QuickaddDrawer code was written like this when I found it. Is there a reason for it to be wrapped in its conditional statement? I've seen other class definitions in this code declared without the conditional.


Solution

  • if(!customElements.get("quickadd-drawer")) {
      customElements.define("quickadd-drawer", class QuickaddDrawer extends HTMLElement {
      ...
      });
    }
    
    class CardBubbles extends QuickaddDrawer {
    ....
    }
    
    customElements.define('card-bubbles', CardBubbles);
    
    

    As explained in the comments QuickaddDrawer is only available within the IF branch scope.

    You could move QuickaddDrawer to a higher scope:

    class QuickaddDrawer extends HTMLElement {
      ...
    });
    if(!customElements.get("quickadd-drawer")) {
      customElements.define("quickadd-drawer", QuickaddDrawer );
    }
    
    class CardBubbles extends QuickaddDrawer {
    ....
    }
    
    customElements.define('card-bubbles', CardBubbles);
    
    

    Or, because Custom Elements ARE Classes, you might as well write:

    if(!customElements.get("quickadd-drawer")) {
      customElements.define("quickadd-drawer", class extends HTMLElement {
      ...
      });
    }
    
    customElements.define('card-bubbles', class extends customElements.get("quickadd-drawer") {
    ....
    });