Search code examples
shopifytypeerrorliquidvariant

Price not updating when selecting a new variant in Shopify


I am trying to edit the Debut theme to better suit my client's needs. Whenever I edit the variant selector in the product-template.liquid file it throws an error and doesn't update the price to the correct variant.

The error:

Uncaught TypeError: Cannot read property 'available' of undefined
    at Product._initVariants (theme.js?v=785054923643579389:8098)
    at new Product (theme.js?v=785054923643579389:8010)
    at Sections._createInstance (theme.js?v=785054923643579389:47)
    at Sections.<anonymous> (theme.js?v=785054923643579389:141)
    at NodeList.forEach (<anonymous>)
    at Sections.register (theme.js?v=785054923643579389:139)
    at HTMLDocument.<anonymous> (theme.js?v=785054923643579389:9467)

The original piece of code is this (this works flawlessly as intended):

<div class="product-form__controls-group">
    {% for option in product.options_with_values %}
        <div class="selector-wrapper js product-form__item">
            <label for="SingleOptionSelector-{{ forloop.index0 }}" >
                {{ option.name }}
            </label>
            <select class="single-option-selector single-option-selector-{{section.id }} product-form__input" id="SingleOptionSelector-{{ forloop.index0 }}" data-index="option{{ forloop.index }}">
                {% for value in option.values %}
                    <option value="{{ value | escape }}"{% if option.selected_value == value %} selected="selected"{% endif %}>{{ value }}</option>
                {% endfor %}
             </select>
        </div>
    {% endfor %}
</div>

which I edited to this (I separated the two because this is what my client needs in his proposed design):

<div class="product-form__controls-group">
    <div class="selector-wrapper js product-form__item">
        <label for="SingleOptionSelector-0">
            Material
        </label>
        <select class="single-option-selector single-option-selector-{{ section.id }} product-form__input" id="SingleOptionSelector-{{ forloop.index0 }}" data-index="option{{ forloop.index }}">
            {% for option in product.options_by_name['Material'].values %}
                {% for value in option %}
                    <option value="{{ value | escape }}"{% if option.selected_value == value %} selected="selected"{% endif %}>{{ value }}</option>
                {% endfor %}
            {% endfor %}
        </select>
    </div>
    <div class="selector-wrapper js product-form__item">
        <label for="SingleOptionSelector-1">
            Size
         </label>
         <select class="single-option-selector single-option-selector-{{ section.id }} product-form__input" id="SingleOptionSelector-{{ forloop.index0 }}" data-index="option{{ forloop.index }}">
             {% for option in product.options_by_name['Size'].values %}
                 {% for value in option %}
                     <option value="{{ value | escape }}"{% if option.selected_value == value %} selected="selected"{% endif %}>{{ value }}</option>
                 {% endfor %}
             {% endfor %}
         </select>
     </div>
</div>

If someone could help me out that would be amazing since the Shopify forum is no help at all.


Solution

  • Your code did not work because, it did not create the required schema that Theme JS was expecting. So it was not able to identify the selected variant. In original code, a data attribute named data-index was specified using this.

    data-index="option{{ forloop.index }}"
    

    However, you did not change it to numerical value as you are not using for loop. So to fix this we have to find the position of option in options array. For that I did this.

        {% for product_option in product.options_with_values %}
            {% if product_option.name == "Material" %}
                {% assign material_index = forloop.index %}
                
            {% elsif  product_option.name == "Size" %}
                {% assign size_index = forloop.index %}
            {% endif %}
        {% endfor %}
    

    Include other options too, if you are using. So the complete working code would be

        {% for product_option in product.options_with_values %}
            {% if product_option.name == "Material" %}
                {% assign material_index = forloop.index %}
                
            {% elsif  product_option.name == "Size" %}
                {% assign size_index = forloop.index %}
            {% endif %}
        {% endfor %}
    
        <div class="product-form__controls-group">
            <div class="selector-wrapper js product-form__item">
                <label for="SingleOptionSelector-0">
                    Material
                </label>
                <select class="single-option-selector single-option-selector-{{ section.id }} product-form__input" id="SingleOptionSelector-{{material_index}}" data-index="option{{material_index}}">
                    {% for option in product.options_by_name['Material'].values %}
                        {% for value in option %}
                            <option value="{{ value | escape }}"{% if option.selected_value == value %} selected="selected"{% endif %}>{{ value }}</option>
                        {% endfor %}
                    {% endfor %}
                </select>
            </div>
            <div class="selector-wrapper js product-form__item">
                <label for="SingleOptionSelector-1">
                    Size
                 </label>
                 <select class="single-option-selector single-option-selector-{{ section.id }} product-form__input" id="SingleOptionSelector-{{size_index}}" data-index="option{{size_index}}">
                     {% for option in product.options_by_name['Size'].values %}
                         {% for value in option %}
                             <option value="{{ value | escape }}"{% if option.selected_value == value %} selected="selected"{% endif %}>{{ value }}</option>
                         {% endfor %}
                     {% endfor %}
                 </select>
             </div>
        </div>