Solved

React to variant change to display/hide text depending on availability

SKlocke
Shopify Partner
18 2 2

I've created a simple snippet to display a text in a Dawn, if the selected/first variant is available

 

{%- if product.selected_or_first_available_variant.available -%}
<div class="shipping-time-container">
<div class="shipping-time-text"><i class="fa-solid fa-check"></i> <span>Auf Lager - In 3-5 Werktagen bei dir!!!!</span></div>
</div>
{%- endif -%}

 Now, when I switch variants, it's not updated because `selected_or_first_available_variant.available` is not re-evaluated. I know, I need to react to the variant change with javascript, but I have no idea how.

I've already found

class VariantSelects extends HTMLElement 

 but I don't think it's the best way to add it this way

Accepted Solution (1)
SKlocke
Shopify Partner
18 2 2

This is an accepted solution.

Thanks for the hint. This is my current solution:

 

1. Loop over all variants and create the correct HTML with data-variant-id, hide it with display: none

{% for variant in product.variants %}
<div style="display: none" data-variant-id="{{ variant.id }}">
   {%- if variant.available -%}
      <div style="display: none">Content Available</div>
   {%- else -%}
      <div style="display: none">Content Not Available</div>
   {%- endif -%}
</div>
{% endfor %}

2. Detect current variant and show the right content

// Add observer to detect url change. This will call "onUrlChange()"
let lastUrl = location.href;
new MutationObserver(() => {
    const url = location.href;
    if (url !== lastUrl) {
        lastUrl = url;
        onUrlChange();
    }
}).observe(document, {subtree: true, childList: true});

// Initialise the correct variant on page load
updateVariants();

// Update variant on url change
function onUrlChange() {
    updateVariants();
}

function updateVariants()
{
    // get the current variantId (or null if initial page load)
    const variantId = getCurrentVariantId();
    // get all created variant contents
    const elements = document.querySelectorAll("[data-variant-id]");
    let first = true;
    elements.forEach(el => {
        let display = 'none'
        // either show the one for the current variantId OR the first one, if no variantId is given (first page load)
        if ((variantId && el.getAttribute('data-variant-id') === variantId) || (!variantId && first)) {
            display = 'block';
        }
        first = false;
        el.style.display = display
    })
}

// get the variantId from the URL (or null if initial page load)
function getCurrentVariantId() {
    const params = new URLSearchParams(window.location.search)
    let variantId = null;
    if (params.has("variant")) {
        variantId = params.get("variant");
    }
    return variantId;
}

View solution in original post

Replies 3 (3)

Andrei_Kuchuk
Shopify Partner
44 5 14

Hi @SKlocke !
Do you have a different url variant parameter on variant change?
If yes you can write js logic to show/hide this message depends on this URL parameter.

For our projects, we made product objects in window (window.productConfig) with variants by keys. And in js logic we have small script to track URL change and update visible message depends on selected variant id.

I think there are possible to avoid tracking variant params in URL just add some id or data-attr to the variants option on the product page.

Andrei Kuchuk, Lead Shopify developer at SpiralScout

Cooperation email: andrey.kuhcuk@spiralscout.com
SKlocke
Shopify Partner
18 2 2

Currently moving everything to a separate app. While give it a try 

SKlocke
Shopify Partner
18 2 2

This is an accepted solution.

Thanks for the hint. This is my current solution:

 

1. Loop over all variants and create the correct HTML with data-variant-id, hide it with display: none

{% for variant in product.variants %}
<div style="display: none" data-variant-id="{{ variant.id }}">
   {%- if variant.available -%}
      <div style="display: none">Content Available</div>
   {%- else -%}
      <div style="display: none">Content Not Available</div>
   {%- endif -%}
</div>
{% endfor %}

2. Detect current variant and show the right content

// Add observer to detect url change. This will call "onUrlChange()"
let lastUrl = location.href;
new MutationObserver(() => {
    const url = location.href;
    if (url !== lastUrl) {
        lastUrl = url;
        onUrlChange();
    }
}).observe(document, {subtree: true, childList: true});

// Initialise the correct variant on page load
updateVariants();

// Update variant on url change
function onUrlChange() {
    updateVariants();
}

function updateVariants()
{
    // get the current variantId (or null if initial page load)
    const variantId = getCurrentVariantId();
    // get all created variant contents
    const elements = document.querySelectorAll("[data-variant-id]");
    let first = true;
    elements.forEach(el => {
        let display = 'none'
        // either show the one for the current variantId OR the first one, if no variantId is given (first page load)
        if ((variantId && el.getAttribute('data-variant-id') === variantId) || (!variantId && first)) {
            display = 'block';
        }
        first = false;
        el.style.display = display
    })
}

// get the variantId from the URL (or null if initial page load)
function getCurrentVariantId() {
    const params = new URLSearchParams(window.location.search)
    let variantId = null;
    if (params.has("variant")) {
        variantId = params.get("variant");
    }
    return variantId;
}