Re: Getting product variant price dynamically

Getting product variant price dynamically

gtn-dev
Visitor
2 0 1

Hello,

 

On the Shopify product page, I have different price variants, and I would like to be able to retrieve the price of the variant selected by the user.

 

How can I do that?

 

This is my code at the moment in main-product.liquid and I'm using Dawn theme:

code.png

The variable 'price' does not update correctly.

 

Thanks for support.

Replies 11 (11)

PaulNewton
Shopify Partner
6814 614 1445

Alot of themes emit their own change event hunt for that and use it.

Try the code without the DOMContentLoaded in browser devtools console panel.

Ensure the element actually exists some themes do wonky things.

Ensure your selectors are targeting the correct element, either specific tag or that there are not multiples and your getting the wrong one. etc etc etc

 

Sight unseen the code seems fine but who knows what else is going on in your theme because you did not provide any inspectable urls so it will always be completed guessworkd for other people.

READ: https://community.shopify.com/c/blog/how-to-get-support-from-the-community/ba-p/2254458 

 

 

 

Contact paull.newton+shopifyforum@gmail.com for the solutions you need


Save time & money ,Ask Questions The Smart Way


Problem Solved? ✔Accept and Like solutions to help future merchants

Answers powered by coffee Thank Paul with a Coffee for more answers or donate to eff.org


gtn-dev
Visitor
2 0 1

Thank you for the support. I'm adding more information about my issue.

    <script>
      document.addEventListener('DOMContentLoaded', function () {
        function isIE() {
          const ua = window.navigator.userAgent;
          const msie = ua.indexOf('MSIE ');
          const trident = ua.indexOf('Trident/');

          return msie > 0 || trident > 0;
        }

        if (!isIE()) return;
        const hiddenInput = document.querySelector('#{{ product_form_id }} input[name="id"]');
        const noScriptInputWrapper = document.createElement('div');
        const variantSwitcher =
          document.querySelector('variant-radios[data-section="{{ section.id }}"]') ||
          document.querySelector('variant-selects[data-section="{{ section.id }}"]');
        noScriptInputWrapper.innerHTML = document.querySelector(
          '.product-form__noscript-wrapper-{{ section.id }}'
        ).textContent;
        variantSwitcher.outerHTML = noScriptInputWrapper.outerHTML;

        document.querySelector('#Variants-{{ section.id }}').addEventListener('change', function (event) {
          hiddenInput.value = event.currentTarget.value;
        });
      });
    </script>

    <script>
            document.addEventListener('DOMContentLoaded', function () {
              // Function to update the price dynamically
              function updatePriceOnVariantChange() {
                const variantSelect =
                  document.querySelector('variant-radios[data-section="{{ section.id }}"]') ||
                document.querySelector('variant-selects[data-section="{{ section.id }}"]');
                const dynamicPriceElement = document.querySelector("[data-pp-amount]");

                // Listen for the change in variant selection
                variantSelect.addEventListener("change", function () {
                const price = {{ product.selected_variant.price | divided_by: 100.00 | json }};
                console.log(price);

                  // Update the price in the data-pp-amount element
                  if (dynamicPriceElement) {
                    dynamicPriceElement.setAttribute("data-pp-amount", price);
                  }
                });
              }

              // Call the function to initialize the price update
              updatePriceOnVariantChange();
            });
    </script>

My site: https://www.luisjw.it/en/products/copia-del-cuore-anatomico-xl?variant=47226652590418

Chirag_Joshi
Shopify Partner
6 0 0

@gtn-dev Hey
Found the Solution, yet?

 

btromero
Shopify Partner
5 0 1

check out my solution above

btromero
Shopify Partner
5 0 1

Any luck on this? it looks like 

{{ product.selected_or_first_available_variant}} or 
{{ product.selected_variant}} is static in the liquid template. Having the exact same issue as you. 
btromero
Shopify Partner
5 0 1

I found the solution to this issue. It's a bit hacky, but since the product.variant is determined by the URL param `variant` we can use this the below method to to check url param changes (which will change on variant change)

<script>
  document.addEventListener('DOMContentLoaded', function () {
    let variants = {{ product.variants | json }};
    let variantPriceDict = {};
    
    variants.forEach(variant => {
      variantPriceDict[variant.id] = variant.price;
    });

    console.log('Variant Price Dictionary:', variantPriceDict);

    function getQueryParam(param) {
      const urlParams = new URLSearchParams(window.location.search);
      return urlParams.get(param);
    }

    function checkVariantPrice() {
      const variantId = getQueryParam('variant');
      if (variantId && variantPriceDict[variantId]) {
        const price = variantPriceDict[variantId];
        console.log(`Variant ID: ${variantId}, Price: ${price}`);
      } else {
        console.log('Variant not found or no variant parameter in URL.');
      }
    }

    checkVariantPrice();


    window.addEventListener('popstate', function () {
      console.log('URL changed:', window.location.href);
      checkVariantPrice();
    });

    const originalPushState = history.pushState;
    history.pushState = function () {
      originalPushState.apply(history, arguments);
      checkVariantPrice();
    };

    const originalReplaceState = history.replaceState;
    history.replaceState = function () {
      originalReplaceState.apply(history, arguments);
      checkVariantPrice();
    };
  });
</script>


using popstate to check for url param changes, we know when a user changes variants and can then use simple logic to match the param against the variant price dictionary created on page load. Not super heavy on client compute as well. It's not elegant but it works. 

Chirag_Joshi
Shopify Partner
6 0 0

Thank you for your response @btromero 

Here is my code, I want to show the selected variation price discount.
How to apply your solution for my code. Can you help please?

<div class="best-price-container">
<p class="best-price">
<span class="best-price-text">BEST PRICE:</span>
<span id="discounted-price-text">Rs.{{
product.price | divided_by: 100 | times: 0.80 | round }}</span>
</p>
</div>

btromero
Shopify Partner
5 0 1

@Chirag_Joshi the line console.log('my discounted price', discountedPrice); will display the discounted price for the selected variant. 

add the below script to your code and check the console logs when you change variants

 

<script>
  document.addEventListener('DOMContentLoaded', function () {
    let variants = {{ product.variants | json }};
    let variantPriceDict = {};
    
    variants.forEach(variant => {
      variantPriceDict[variant.id] = variant.price;
    });

    console.log('Variant Price Dictionary:', variantPriceDict);

    function getQueryParam(param) {
      const urlParams = new URLSearchParams(window.location.search);
      return urlParams.get(param);
    }

    function updatePriceDisplay(price) {
      const discountedPrice = (price / 100 * 0.80).toFixed(2);
      console.log('my discounted price', discountedPrice); 
      const priceElement = document.getElementById('discounted-price-text');
      if (priceElement) {
        priceElement.innerText = `Rs.${discountedPrice}`;
      }
    }

    function checkVariantPrice() {
      const variantId = getQueryParam('variant');
      if (variantId && variantPriceDict[variantId]) {
        const price = variantPriceDict[variantId];
        console.log(`Variant ID: ${variantId}, Price: ${price}`);
        updatePriceDisplay(price);
      } else {
        console.log('Variant not found or no variant parameter in URL.');
      }
    }

    checkVariantPrice();

    window.addEventListener('popstate', function () {
      console.log('URL changed:', window.location.href);
      checkVariantPrice();
    });

    const originalPushState = history.pushState;
    history.pushState = function () {
      originalPushState.apply(history, arguments);
      checkVariantPrice();
    };

    const originalReplaceState = history.replaceState;
    history.replaceState = function () {
      originalReplaceState.apply(history, arguments);
      checkVariantPrice();
    };
  });
</script>

 

 

Chirag_Joshi
Shopify Partner
6 0 0

Its working like a charm. @btromero  I don't know how to thank you. I really appreciate your help.

Chirag_Joshi
Shopify Partner
6 0 0

@btromero 
When going to the product page, It calculates the discounts as per the lowest price first, so if the largest priced variation is selected by default it will show the discounted price of the lowest variation. When we select the other variations then it shows the proper prices. Can we fix it?

Also can we show the store currency here instead of Rs. : <span id="discounted-price-text">Rs.{{
product.price | divided_by: 100 | times: 0.80 | round }}</span>


Thank you,

btromero
Shopify Partner
5 0 1

@Chirag_Joshi I don't know much about currencies, so i don't know how to help there. To get around the issue with the pricing, you can set up 2 sets of logic.

domcontentload logic (when page first loads) use 

{{ product.selected_or_first_available_variant }} to get the price of the initial loaded variant (on page load)

when variant change, use my logic above. 

document.addEventListener('DOMContentLoaded', function () {
let variants = {{ product.variants | json }};
let variantPriceDict = {};

variants.forEach(variant => {
variantPriceDict[variant.id] = variant.price;
});

just add a variable here for const initialSelectedVariant = {{ product.selected_or_first_available_variant }}; and grab that price