Product swatches not updating in cart (taking originally selected product on page reload)

Highlighted
Shopify Partner
4 0 0

Everything is working but swatch selections are not updating once "Add to Cart" is clicked (whatever the originally selected swatch was is being selected. Please advise!

 

product.liquid

<div data-section-id="{{ section.id }}" data-section-type="product" data-enable-history-state="true">
  <form action="/cart/add" method="post" enctype="multipart/form-data">

    {%- assign current_variant = product.selected_or_first_available_variant -%}
    {%- assign featured_image = current_variant.featured_image | default: product.featured_image -%}
    {% capture productTitle %}{% include 'product-title' %}{% endcapture %}
    {% capture productPrice %}{% include 'product-price' %}{% endcapture %}
    {%- capture image_alt_text -%}
      {{ productTitle }} - {{ shop.name }}
    {%- endcapture -%}

    {% if product.images.size > 1 %}
      <ul class="productThumbs">
        {% for image in product.images %}
          <li>
            <a href="{{ image.src | img_url: '480x480' }}" data-thumbnail-id="{{ image.id }}" data-product-single-thumbnail>
              <img class="product-single__thumbnail-image" src="{{ image.src | img_url: '50x' }}" alt="{{ image_alt_text }}">
            </a>
          </li>
        {% endfor %}
      </ul>
    {% endif %}

    <div class="mobileOnly">
      <div class="vendor">{{ product.vendor }}</div>
      <h1 class="title">{{ productTitle }}</h1>
    </div>


    <div class="mainImage">
      {% assign counter = 0 %}

      {% for image in product.images %}
        {% capture wrapper_class %}
          {%- unless featured_image == image -%}
            hide
          {%- endunless -%}
        {% endcapture %}

        {% capture image_attributes %}
          data-product-featured-image data-large="{{ image | img_url: '2048x2048' }}"
        {% endcapture %}

        <div class="img-zoom-container {{ wrapper_class }}">
          {% include 'responsive-image' with
            image: image,
            max_width: 2048,
            max_height: 2048,
            image_attributes: image_attributes,
            image_class: 'image-zoom',
            wrapper_class: wrapper_class,
            wrapper_attributes: "data-product-image-wrapper",
            image_alt: image_alt_text
          %}
          <div class="zoomedContainer secret"><div id="zoomed-Image-{{ image.id }}-{{ counter }}" class="img-zoom-result"></div></div>

          <span class="imageInstructions">Roll over image to zoom in</span>
        </div>

        {% assign counter = counter | plus: 1 %}

      {% endfor %}
    </div>

    <div class="quickInfo">

      <h1 class="title desktopOnly">{{ productTitle }}</h1>

      <div class="vendor desktopOnly">by {{ product.vendor }}</div>

      {{ productPrice }}

      <div class="rte">
        <div class="description desktopOnly">
          {{ product.description }}
        </div>

        {% include 'product-variants' %}
      </div>

    </div>

    <div class="actionsBoxContainer">

      {% if section.settings.show_share_buttons %}
        <div class="socialSharingBox desktopOnly">
          <span class="shareButtonInstructions">Share</span>
          {% include 'social-sharing', share_title: productTitle, share_permalink: product.url, share_image: product %}
        </div>
      {% endif %}

      <div class="actionsBox">

        {{ productPrice }}

        {% if product.available %}
          <div class="stock inStock">In Stock.</div>
        {% else %}
          <div class="stock noStock">Out of Stock.</div>
        {% endif %}

        <div class="shipsFrom desktopOnly">
          Ships from and sold by {{ shop.name }}.
        </div>

        <div class="quantity visually-hidden">
          <label for="Quantity">{{ 'products.product.quantity' | t }}</label>
          <input type="number" id="Quantity" name="quantity" value="1" min="1">
        </div>

        <button
          type="submit"
          name="add"
          class="button"
          data-add-to-cart
          {% unless current_variant.available %}disabled="disabled"{% endunless %}
          {% unless current_variant.price != 0 %}disabled="disabled"{% endunless %}>
            <span data-add-to-cart-text>
              {% if current_variant.available %}
                <span class="icon">{% include 'icon-cart' %}</span>
                <span class="text">{{ 'products.product.add_to_cart' | t }}</span>
              {% else %}
                <span class="soldOut">{{ 'products.product.sold_out' | t }}</span>
              {% endif %}
            </span>
        </button>

        <div class="shipsFrom mobileOnly">
          Ships from and sold by {{ shop.name }}.
        </div>

        {% include 'deliver-to' %}

      </div>

      <h2 class="about mobileOnly">About this item</h2>

      <div class="moreInfo mobileOnly">
        
        <div class="description">{{ product.description }}</div>

        {% include 'product-variants' %}
      </div>

      {% if section.settings.show_share_buttons %}
        <div class="socialSharingBox mobileOnly">
          <span class="shareButtonInstructions">Share</span>
          {% include 'social-sharing', share_title: productTitle, share_permalink: product.url, share_image: product %}
        </div>
      {% endif %}

    {% unless product == empty %}
      <script type="application/json" data-product-json>
        {{ product | json }}
      </script>
    {% endunless %}

  </form>

</div>

{% schema %}
  {
    "name": "Product pages",
    "settings": [
      {
        "type": "checkbox",
        "id": "show_share_buttons",
        "label": "Show social sharing buttons",
        "default": true
      }
    ]
  }
{% endschema %}

{% javascript %}

  $( document ).ready(function() {

    function imageZooming() {

      var windowWidth = $(window).width();

      if (windowWidth >= 1300) {

        $('.imageInstructions').show();

        $('.img-zoom-container').on({
            mouseenter: function () {
                $(this).children('.responsive-image__wrapper').children('.img-zoom-lens').removeClass('secret');
                $(this).children('.zoomedContainer').removeClass('secret');

                $('.imageInstructions').html('Click image to open expanded view');
            },
            mouseleave: function () {
                $(this).children('.responsive-image__wrapper').children('.img-zoom-lens').addClass('secret');
                $(this).children('.zoomedContainer').addClass('secret');

                $('.imageInstructions').html('Roll over image to zoom in');
            }
        });

        $('.img-zoom-container img.image-zoom').each(function() {
          var zoomedId = "zoomed-" + this.id;
          imageZoom(this.id, zoomedId);
        });
      } else {
        $('.imageInstructions').hide();
      }
    }

    $(window).resize(function(){
      imageZooming();
    });

    imageZooming();
    
  });
  
{% endjavascript %}

product-variants.liquid

<div class="variants">
  {% unless product.has_only_default_variant %}
    {% for option in product.options_with_values %}
      {%- capture optionValuesSize -%}{{ option.values | size  }}{%- endcapture -%}

      <div class="selector-wrapper js swatch option{% if optionValuesSize == '1' %} oneOption{% endif %}">
        {%- assign i = forloop.index0 -%}
        <h5 class="name">{{ option.name }}</h5>
        <div class="values">
          {% for value in option.values %}            
            <input class="swatch-element" id="SingleOptionSelector-{{ i }}-{{ value | handle }}" data-single-option-selector data-index="option{{ option.position }}" type="radio" name="SingleOptionSelector-{{ i }}" value="{{ value | escape }}"{% if option.selected_value == value %} checked{% endif %}  {% unless current_variant.available %}disabled="disabled"{% endunless %} >
            <label for="SingleOptionSelector-{{ i }}-{{ value | handle }}" {% if optionValuesSize == '1' %}class="onlyOption"{% endif %}><span>{{ value }}</span></label>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  {% endunless %}

  {% if current_variant.sku != blank %}
    <div class="option sku">
      <h5 class="name">Item #</h5>
      <span class="value">{{ current_variant.sku }}</span>
    </div>
  {% endif %}

  <select name="id" class="no-js" data-product-select>
    {% for variant in product.variants %}
      <option
        {% if variant == current_variant %}selected="selected"{% endif %}
        {% unless variant.available %}disabled="disabled"{% endunless %}
        value="{{ variant.id }}">
          {{ variant.title }}
      </option>
    {% endfor %}
  </select>
</div>

product.js

/**
 * Product Template Script
 * ------------------------------------------------------------------------------
 * A file that contains scripts highly couple code to the Product template.
 *
 * @namespace product
 */

import $ from 'jquery';
import Variants from '@shopify/theme-variants';
import {formatMoney} from '@shopify/theme-currency';
import {register} from '@shopify/theme-sections';

const selectors = {
  addToCart: '[data-add-to-cart]',
  addToCartText: '[data-add-to-cart-text]',
  comparePrice: '[data-compare-price]',
  comparePriceText: '[data-compare-text]',
  originalSelectorId: '[data-product-select]',
  priceWrapper: '[data-price-wrapper]',
  productImageWrapper: '[data-product-image-wrapper]',
  productFeaturedImage: '[data-product-featured-image]',
  productJson: '[data-product-json]',
  productPrice: '[data-product-price]',
  productThumbs: '[data-product-single-thumbnail]',
  singleOptionSelector: '[data-single-option-selector]',
};

const cssClasses = {
  activeThumbnail: 'active-thumbnail',
  hide: 'hide',
};

const keyboardKeys = {
  ENTER: 13,
};

/**
 * Product section constructor. Runs on page load as well as Theme Editor
 * `section:load` events.
 * @param {string} container - selector for the section container DOM element
 */

register('product', {
  onLoad() {
    this.$container = $(this.container);
    this.namespace = `.${this.id}`;

    // Stop parsing if we don't have the product json script tag when loading
    // section in the Theme Editor
    if (!$(selectors.productJson, this.$container).html()) {
      return;
    }

    this.productSingleObject = JSON.parse(
      $(selectors.productJson, this.$container).html(),
    );

    const options = {
      $container: this.$container,
      enableHistoryState: this.$container.data('enable-history-state') || false,
      singleOptionSelector: selectors.singleOptionSelector,
      originalSelectorId: selectors.originalSelectorId,
      product: this.productSingleObject,
    };

    this.settings = {};
    this.variants = new Variants(options);
    this.$featuredImage = $(selectors.productFeaturedImage, this.$container);

    this.$container.on(
      `variantChange${this.namespace}`,
      this.updateAddToCartState.bind(this),
    );
    this.$container.on(
      `variantPriceChange${this.namespace}`,
      this.updateProductPrices.bind(this),
    );

    if (this.$featuredImage.length > 0) {
      this.$container.on(
        `variantImageChange${this.namespace}`,
        this.updateImages.bind(this),
      );
    }

    $( ".swatch input.swatch-element" ).click(function() {

      // console.log(this);

      // $(".swatch input.swatch-element").each(function() {
      //   $(this).prop('checked', false);  
      // });

      // var checkbox = ".swatch input#" + this.id;

      // $(checkbox).prop('checked', !$(checkbox).prop('checked'));

      $(".swatch label.selectedOnLoad").each(function() { 
        $(this).removeClass("selectedOnLoad");
      });
    });

    this.highlightSelectedVariantOnLoad();
    this.initImageSwitch();
  },

  highlightSelectedVariantOnLoad() {
    $(".swatch input.swatch-element:checked").each(function() { 
      $(".swatch label[for='" + this.id + "']").addClass("selectedOnLoad");  
    });
  },

  initImageSwitch() {
    const $productThumbs = $(selectors.productThumbs, this.$container);

    if (!$productThumbs.length) {
      return;
    }

    $productThumbs
      .on('click', (evt) => {
        evt.preventDefault();
        const imageId = $(evt.currentTarget).data('thumbnail-id');
        this.switchImage(imageId);
        this.setActiveThumbnail(imageId);
      })
      .on('keyup', this.handleImageFocus.bind(this));
  },

  handleImageFocus(evt) {
    if (evt.keyCode !== keyboardKeys.ENTER) {
      return;
    }

    this.$featuredImage.filter(':visible').focus();
  },

  setActiveThumbnail(imageId) {
    let newImageId = imageId;

    // If "imageId" is not defined in the function parameter, find it by the current product image
    if (typeof newImageId === 'undefined') {
      newImageId = $(
        `${selectors.productImageWrapper}:not('.${cssClasses.hide}')`,
      ).data('image-id');
    }

    const $thumbnail = $(
      `${selectors.productThumbs}[data-thumbnail-id='${newImageId}']`,
    );

    $(selectors.productThumbs)
      .removeClass(cssClasses.activeThumbnail)
      .removeAttr('aria-current');

    $thumbnail.addClass(cssClasses.activeThumbnail);
    $thumbnail.attr('aria-current', true);
  },

  switchImage(imageId) {
    const $newImage = $(
      `${selectors.productImageWrapper}[data-image-id='${imageId}']`,
      this.$container,
    );
    const $otherImages = $(
      `${selectors.productImageWrapper}:not([data-image-id='${imageId}'])`,
      this.$container,
    );
    $newImage.removeClass(cssClasses.hide);
    $otherImages.addClass(cssClasses.hide);
  },

  /**
   * Updates the DOM state of the add to cart button
   *
   * @param {boolean} enabled - Decides whether cart is enabled or disabled
   * @param {string} text - Updates the text notification content of the cart
   */
  updateAddToCartState(evt) {
    const variant = evt.variant;

    if (variant) {
      $(selectors.priceWrapper, this.$container).removeClass(cssClasses.hide);
    } else {
      $(selectors.addToCart, this.$container).prop('disabled', true);
      $(selectors.priceWrapper, this.$container).addClass(cssClasses.hide);
      return;
    }

    if (variant.available) {
      $(selectors.addToCart, this.$container).prop('disabled', false);
    } else {
      $(selectors.addToCart, this.$container).prop('disabled', true);
    }

    if (variant.price != 0) {
      $(selectors.addToCart, this.$container).prop('disabled', false);
    } else {
      $(selectors.addToCart, this.$container).prop('disabled', true);
    }
  },

  updateImages(evt) {
    const variant = evt.variant;
    const imageId = variant.featured_image.id;

    this.switchImage(imageId);
    this.setActiveThumbnail(imageId);
  },

  /**
   * Updates the DOM with specified prices
   *
   * @param {string} productPrice - The current price of the product
   * @param {string} comparePrice - The original price of the product
   */
  updateProductPrices(evt) {
    const variant = evt.variant;
    const $comparePrice = $(selectors.comparePrice, this.$container);
    const $compareEls = $comparePrice.add(
      selectors.comparePriceText,
      this.$container,
    );

    const freeText = $('.freeText').html();

    if (variant.price == 0) {
      $(selectors.productPrice, this.$container).html(
        freeText,
      );
    }  else {
      $(selectors.productPrice, this.$container).html(
        formatMoney(variant.price, theme.moneyFormat),
      );
    }

    if (variant.compare_at_price > variant.price) {
      $comparePrice.html(
        formatMoney(variant.compare_at_price, theme.moneyFormat),
      );
      $compareEls.removeClass(cssClasses.hide);
    } else {
      $comparePrice.html('');
      $compareEls.addClass(cssClasses.hide);
    }
  },

  /**
   * Event callback for Theme Editor `section:unload` event
   */
  onUnload() {
    this.$container.off(this.namespace);
  },
});
0 Likes
Shopify Partner
4 0 0

This is URGENT! Any help ASAP would be hugely appreciated. Compensation can be provided if necessary.

0 Likes