Toggle language of labels in flask wtforms form - javascript

I have a series of wtforms written in a flask app. One of my pages in my app will be used by people speaking English and Spanish. I would like to find a clean way of toggling the form element labels between English and Spanish with a toggle button on the webpage.
I found a nice solution to toggle languages using the HTML lang attribute here (2nd answer down, by J Grover):
Using Javascript to change website language
This encloses each language in a <span> element and then simply hides the one we don't want to see.
My problem is that the labels for the fields on my forms are coming from wtforms objects. I am unsure how to include multiple languages in my current setup. See below for an example of where I am now:
Form
class RoofCheck(FlaskForm):
"""
Class holding the form inputs for a roof check
"""
roofstate = RadioField('Roof Status',
validators=[validators.DataRequired('Please select roof closed or open')],
choices=[('closed', 'Closed'), ('open', 'Open')])
comments = TextAreaField('Comments on roof status',
[validators.optional(), validators.length(max=390)],
render_kw={"placeholder": "Enter comments here",
"rows": 4,
"style": "min-width: 100%"})
submit = SubmitField('Submit')
HTML
<div id='roof_check' class='col-md-6 padding-0'>
<form id="roof_check_form" action={{ url_for('roof_check')}} method="post" name="roof">
<fieldset class='form_group'>
{{ form1.hidden_tag() }}
<legend class='text-center'>
Daily visual check of the roof
</legend>
{% for subfield in form1.roofstate %}
<div class='form-check'>
{{ subfield }}
{{ subfield.label(class_="form-check-label") }} <br/>
</div>
{% endfor %}
<div class='form-check'>
{{ form1.comments }}
</div>
<div class='form-check'>
{% with messages = get_flashed_messages(category_filter=["form1"]) %}
{% if messages %}
{% for message in messages %}
<div> {{ message }} </div>
{% endfor %}
{% endif %}
{% endwith %}
{% for message in form1.roofstate.errors %}
<div> {{ message }} </div>
{% endfor %}
<div style="padding-top: 5px;">
{{ form1.submit(class_="btn btn-primary") }}
</div>
</div>
</fieldset>
</form>
</div>
I am not sure where to begin adding multiple labels to the RoofCheck class form objects. Any advice on how to insert support for two languages here would be great. Thanks in advance.

So it turns out that I can just add html directly to the label and place the language attribute there, then use the javascript solution in the link above to toggle the language. For example:
roof_status_text = ("<span lang='en'>Roof Status</span>"
"<span lang='es'>Estado del Techo</span>")
open_text = ("<span lang='en'>Open</span>"
"<span lang='es'>Abierto</span>")
closed_text = ("<span lang='en'>Closed</span>"
"<span lang='es'>Cerrado</span>")
roofstate = RadioField(roof_status_text,
validators=[validators.DataRequired('Please select roof closed or open')],
choices=[('closed', closed_text),
('open', open_text)])

Related

Populate text fields on select field update in Flask / WTForms

Folks, scratching my head at this, there's a kind of an answer to this here, but having difficulty implementing it.
I currently have a recipe and styles table, and when submit an "add recipe" form, it copies data from the styles table into the recipe. What I would like to do is to select a style in the add recipe form and have this data populate form fields. So I'd like style-type for example to be populated in the form on updating the style select dropdown.
My set up:
Routes:
#app.route('/recipe/new', methods=['GET', 'POST'])
#login_required
def addrecipe():
form = RecipeForm()
if form.validate_on_submit():
recipe = Recipe(recipe_name=form.recipe_name.data,
recipe_style=form.style.data.id,
style_name=form.style.data.name,
style_type = form.style.data.type)
db.session.add(recipe)
db.session.commit()
flash('You added your recipe, get brewing!', 'success')
return redirect(url_for('recipes'))
return render_template('add_recipe.html', title = 'Add Recipe', form=form, legend='Add Recipe')
Models:
class Recipe(db.Model):
id = db.Column(db.Integer, primary_key=True)
recipe_name = db.Column(db.String(100), nullable=False)
recipe_style = db.Column(db.Text, db.ForeignKey('styles.id'))
style_name = db.Column(db.String(100))
style_type = db.Column(db.String(100))
# used for query_factory
def getStyles():
return Styles.query.order_by(Styles.name.asc())
Forms:
class RecipeForm(FlaskForm):
recipe_name = StringField('Recipe Name', validators=[DataRequired(), Length(min=2, max=20)])
style = QuerySelectField(query_factory=getStyles,
get_label="name")
style_type = StringField('Style Type')
The Form HTML:
<form method="POST" action="">
{{ form.hidden_tag() }}
<legend class="border-bottom mb-4">{{ legend }}</legend>
<fieldset class="form-group card p-3 bg-light">
<h5 class="card-title">Overview</h5>
<div class="form-row">
<div class="form-group col-md-3">
{{ form.recipe_name.label(class="form-control-label") }}
{% if form.recipe_name.errors %}
{{ form.recipe_name(class="form-control form-control-sm is-invalid") }}
<div class="invalid-feedback">
{% for error in form.recipe_name.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.recipe_name(class="form-control form-control-sm") }}
{% endif %}
</div>
</fieldset>
<fieldset class="form-group card p-3 bg-light">
<h5 class="card-title">Style</h5>
<div class="form-row">
<div class="form-group col-md-3">
{{ form.style.label(class="form-control-label") }}
<input class="form-control form-control-sm" type="text" placeholder="Search Styles" id="myInput" onkeyup="filterFunction()">
{% if form.style.errors %}
{{ form.style(class="form-control form-control-sm is-invalid") }}
<div class="invalid-feedback">
{% for error in form.style.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.style(class="form-control form-control-sm", id="style_name") }}
{% endif %}
</div>
<div class="form-group col-md-2">
{{ form.style_type.label(class="form-control-label") }}
{% if form.style_type.errors %}
{{ form.style_type(class="form-control form-control-sm is-invalid") }}
<div class="invalid-feedback">
{% for error in form.style_type.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.style_type(class="form-control form-control-sm", id="styletype", style_type_tag='{{ form.style.data.type }}' ) }}
{% endif %}
</div>
</div>
</fieldset>
My Javascript so far:
style_name.oninput = function(o) {
// style = document.getElementById('styletype')
styletype.value = $(o).attr('style_type_tag')
}
I can get some basic stuff working with the JS function. So when I update the dropdown, it'll populate the field with some text. What I can't figure out is how to pull the style_type info from the database. The link at the top here loads that info into the html tags of the text box, but it's a little different to what I'm doing. The poster has looped through some items and it isn't a form. My style_type_tag is just showing up as the raw text. I'm guessing that the loop here is crucial but I can't quite make the step to getting into my setup.
Any help much appreciated!
So the answer to this was building a simple API. I'm sure there are simpler methods, but I wanted a bit of practice here and thought it would be useful in building other features into the project.
I followed Brad Traversy's vid on the subject and used the GET section to make this. His project was a simple single file project, so I had to get a bit more involved with imports etc in my project.
Grab postman to interact with the API
Install Marshmallow, To requirements.txt, add the lines:
flask-marshmallow
marshmallow-sqlalchemy
then run
pip install -r requirements.txt
Import and initialise marshmallow. In init.py:
from flask_marshmallow import Marshmallow
ma = Marshmallow(app)
Add style schema To models.py
# import module
from flaskblog import ma
# create schema with the fields required
class StyleSchema(ma.Schema):
class Meta:
fields = ("id", "name", "origin", "type")
# initialise single style schema
style_schema = StyleSchema()
# initialise multiple style schema
styles_schema = StyleSchema(many=True)
Note that the strict=True isn't necessary any more with Marshmallow.
Create endpoints/routes, to routes.py:
# Get All Styles
#app.route('/styleget', methods=['GET'])
def styles_get():
all_styles = Styles.query.all()
result = styles_schema.dump(all_styles)
# return jsonify(result.data) - note that this line is different to the video, was mentioned in the comments. Was originally "return jsonify(result.data)"
return styles_schema.jsonify(all_styles)
# Get Single Product
# passes the id into the URL
#app.route('/styleget/<id>', methods=['GET'])
def style_get(id):
style = Styles.query.get(id)
return style_schema.jsonify(style)
Update JS script:
style_name.onchange = function() {
// creates a variable from the dropdown
style = document.getElementById('style_name').value
// uses the variable to call the API and populate the other form fields
fetch('/styleget/' + style).then(function(response) {
response.json().then(function(data) {
// this takes the 'type' data from the JSON and adds it to the styleType variable
styleType = data.type;
// adds the data from the variable to the form field using the ID of the form.
styletype.value = styleType
});
});
}
Hope this helps anyone who runs into the same challenge!

Assign color to text in website based on ID in database

In my forums website, I want to assign a certain color to each role. For example the admin color is blue, so the username of this admin is always blue. In my database, I'm using MySQL, I have a role table that assigns an ID for each role and a users table linked to the role table.
How can I assign the color I want to the role ID that I want?
Note: I'm using Django for my back-end work
Thank you.
This is what I've tried so far.
<div class="username"> <a id= "usercolor" style="color: white; cursor: pointer;"
onclick="openmodal( {{ instance.author.id }})"> {{ instance.author.Username }}
</a>
<script>
{% if instance.author.Role.RoleName == "Admin" %}
document.getElementById("usercolor").style.color="blue";
{% endif %}
</script>
<br>
</div>
I assigned a default color white to the username inside the forum and gave it an id. I then took the RoleName column in my userrole table from the database and using if statement and document.getElementById I tried to make it that only the admin color is blue. This only changed the color of the first admin as shown in the image here
Javascript lets you assign keys and values in arbitrary pairs. For instance, you could set your role/color combos with a structure like this:
const roleColors = {
admin: "goldenrod",
moderator: "purple",
notableTroll: "olive",
}
This would let you get the color associated with a role, such as admin with
const adminColor = roleColors.admin;
or, assuming you had a user object with a role property shaped like
{
username: "JimNaysium",
role: "admin"
}
you could get the user's role with
const adminColor = roleColors[user.role];
If you want to have this in a function, instead of a direct lookup, you could do something like:
function getColorByRole(role) {
const roleColors = {
admin: "goldenrod",
moderator: "purple",
troll: "olive",
};
return roleColors[role];
}
Good luck and happy coding.
To answer my own post even though delayed. I used Django instance and an if condition for each role ID as follows:
{% for instance in item %}
<div class="post">
<div class="body">
<div class="authors">
<div class="row">
<img class="account-info-sub2" style="border-radius:50%" src="{{ instance.author.user_thumbnail.url }}" alt="error">
<div class="username"> <a class="{% if instance.author.Role.RoleName == 'User' %} shimmeruser {% elif instance.author.Role.RoleName == 'Admin' %} shimmeradmin {% elif instance.author.Role.RoleName == 'Forum Moderator' %} shimmermoderator {% elif instance.author.Role.RoleName == 'Customer Service' %} shimmerservice {% endif %}" style="cursor:pointer;" onclick="openmodal( {{ instance.author.id }})"> {{ instance.author.Username }} </a>
<br>
</div>
<div class="rolemob">
<div class="account-info-sub2">{{ instance.author.Role.RoleName }} </div>
</div>
</div>
As you can see in the if condition, if the author of the post has a rolename of Admin his colour should be the one assigned in the "shimmeradmin" CSS. "author", "Role" and "RoleName" are all from the database. Ignore the div tags, they're not wrong I just didn't copy the whole code obviously.
To summarize. What you need to do understand is this line of code:
<div class="username"> <a class="{% if instance.author.Role.RoleName == 'User' %} shimmeruser {% elif instance.author.Role.RoleName == 'Admin' %} shimmeradmin {% elif instance.author.Role.RoleName == 'Forum Moderator' %} shimmermoderator {% elif instance.author.Role.RoleName == 'Customer Service' %} shimmerservice {% endif %}" style="cursor:pointer;" onclick="openmodal( {{ instance.author.id }})"> {{ instance.author.Username }} </a>

Show and hide text of different posts

I have several posts each of them composed of three parts : a title, a username/date and a body. What I want to do is to show the body when I click on either the title or the username/date and hide it if I click on it again. What I've done so far works but not as expected because when I have two or more posts, it only shows the body of the last post even if I click on another post than the last one. So my goal is only to show the hidden text body corresponding to the post I'm clicking on. Here is my code:
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Test page{% endblock %}</h1>
<a class="action" href="{{ url_for('main_page.create') }}">New</a>
{% endblock %}
{% block content %}
{% for post in posts %}
<article class="post">
<header>
<script language="JavaScript">
function showhide(newpost)
{var div = document.getElementById(newpost);
if (div.style.display !== "block")
{div.style.display = "block";}
else {div.style.display = "none";}}
</script>
<div onclick="showhide('newpost')">
<h1>{{ post['title'] }}</h1>
<div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%d-%m-%Y') }}</div>
</div>
</header>
<div id="newpost">
<p class="body">{{ post['body'] }}</p>
</div>
</article>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}
Of course I looked for a solution as much as I could but I'm kind of stuck plus I'm a complete beginner in HTML/JS/CSS. And one last thing, I'm currently using Python's framework Flask. Thank you by advance.
You need to give each of your posts a unique id for your approach to work.
Change your code to
<div id="{{post_id}}">
<p class="body">{{ post['body'] }}</p
</div>
where post_id is that post's unique id e.g. its id in the database you are using that you pass to the template in your view. Then, change the call to the onclick event handler to
<div onclick="showhide('{{post_id}}')">
If you don't have a unique id you can also use the for loop's index: replace all post_id instances above with loop.index. See Jinja's for loop docs for more information.

How do I populate dynamically a StringField with the value of a SelectField in Wtforms

in a wtforms, I would like my SelectField to fill up with its selected value a StringField.
I use flask, bootstrap, and python 3.7
My HTML code is as follow:
{% block body %}
<h3>Edit Bloomberg ticker details</h3>
{% from "includes/forms/_form_helpers.html" import render_field %}
<div class="form-group" id="company_id" onchange="myFunction(event)">
{{render_field(form.company_names, class_="form-control")}}
</div>
<div class="form-group" id="isin_id">
{{render_field(form.isin_id, class_="form-control")}}
</div>
<script>
function myFunction(e) {
document.getElementById("isin_id").value = e.target.value
}
</script>
{% endblock %}
And the pyhon behind is as follow:
class DefTickerForm(_Form):
choices_companies = [(1,'Facebook'), (2, 'Google') ]
company_names = _SelectField(label='Company names:', choices=choices_companies, coerce=int)
isin_id = _StringField(label='isin_id', validators=[_validators.DataRequired], default=-1)
I would like that when the user select 'Facebook', the isin SelectField to be equal to 1. But so far it does nothing.
Note that if if code:
alert(e.target.value)
I get the wanted value. so issue is to set the TextField value.
my render field code is as followed (from a youtube tutorial):
{% macro render_field(field) %}
{{ field.label }}
{{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
<span class="help-inline"> {{ error }}</span>
{% endfor %}
{% endif %}
{% endmacro %}
Any help would be much apreciated as google isn't so good on these.
Best
apparently TextField only accepts strings (I guess obvious if you are used to javascript)
so code working is as follow in case someone get he same problem:
<div class="form-group" onchange="myFunction(event)">
{{render_field(form.company_names, class_="form-control")}}
</div>
<div class="form-group">
{{render_field(form.isin_id, class_="form-control")}}
</div>
<script>
function myFunction(e) {
var x = e.target.value;
alert(x);
document.getElementById("isin_id").value = x.toString();
}
</script>
As a note, Jinja or anyway my render, use the fields names as default IDs (wich i realised using Chrome inpector. Meaning I didn't have to add an id for each Div. Anyway that is the thoughts of a beginenr in Javascripts.

Shopify Product Page to hide variant images

I am sort of new with Shopify and I´ve been playing around with it for the ast week or so without much success when trying to solve my issue.
I am currently using the Brooklyn template and the way they represent the Product Page doesn´t precisely give the best user experience. The way it´s representing the images by default is by having all the product variants images showed to the customer all the time even if he hasn´t actually picket that variant (i.e. a specific colour for the product). It also displays all the product images in a vertical way which makes navigation for the user quite frustrating if you have more than a couple of pictures per product variant.
I´ve found online a tutorial ( http://littlesnippets.ca/blogs/tutorials/15665261-grouping-images-with-variants )that addresses the part of my issue to hide the pictures of the variants that are not selected by the customer, and show them once the user click on it.(you can see an example of what I want here http://group-variant-images.myshopify.com/collections/frontpage/products/anson-chair ). This is more or less how it looks my site now (https://themes.shopify.com/themes/brooklyn/styles/brooklyn/preview).
The problem is that that tutorial is being applied to a website that is not using the exact theme/functionality that Ii do, although it´s similar.
I´ve failed to apply those changes to my theme, can anybody give me a hand?
This is my product.liquid piece of code at the moment:
<!-- /templates/product.liquid -->
<div itemscope itemtype="http://schema.org/Product">
<meta itemprop="url" content="{{ shop.url }}{{ product.url }}">
<meta itemprop="image" content="{{ product.featured_image.src | img_url: 'grande' }}">
{% assign current_variant = product.selected_or_first_available_variant %}
<div class="grid product-single">
<div class="grid__item large--seven-twelfths medium--seven-twelfths text-center">
<div class="product-single__photos">
{% assign featured_image = current_variant.featured_image | default: product.featured_image %}
{% comment %}
Display current variant image, or default first
{% endcomment %}
<div class="product-single__photo-wrapper">
<img class="product-single__photo" id="ProductPhotoImg" src="{{ featured_image | img_url: 'grande' }}" {% if settings.product_zoom_enable %}data-mfp-src="{{ featured_image | img_url: '1024x1024' }}"{% endif %} alt="{{ featured_image.alt | escape }}" data-image-id="{{ featured_image.id }}">
</div>
{% comment %}
Display rest of product images, not repeating the featured one
{% endcomment %}
{% for image in product.images %}
{% unless image contains featured_image %}
<div class="product-single__photo-wrapper">
<img class="product-single__photo" src="{{ image.src | img_url: 'grande' }}" {% if settings.product_zoom_enable %}data-mfp-src="{{ image.src | img_url: '1024x1024' }}"{% endif %} alt="{{ image.alt | escape }}" data-image-id="{{ image.id }}">
</div>
{% endunless %}
{% endfor %}
</div>
</div>
<div class="grid__item product-single__meta--wrapper medium--five-twelfths large--five-twelfths">
<div class="product-single__meta">
{% if settings.product_vendor_enable %}
<h2 class="product-single__vendor" itemprop="brand">{{ product.vendor }}</h2>
{% endif %}
<h1 class="product-single__title" itemprop="name">{{ product.title }}</h1>
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
{% comment %}
Optionally show the 'compare at' or original price of the product.
{% endcomment %}
{% if product.compare_at_price_max > product.price %}
<span class="product-single__price--wrapper">
<span class="visually-hidden">{{ 'products.general.regular_price' | t }}</span>
<span id="ComparePrice" class="product-single__price--compare-at">
{% if current_variant.compare_at_price > current_variant.price %}
{{ current_variant.compare_at_price | money }}
{% endif %}
</span>
<span class="visually-hidden">{{ 'products.general.sale_price' | t }}</span>
</span>
{% endif %}
<span id="ProductPrice" class="product-single__price{% if product.compare_at_price > product.price %} on-sale{% endif %}" itemprop="price">
{{ current_variant.price | money }}
</span>
<hr class="hr--small">
<meta itemprop="priceCurrency" content="{{ shop.currency }}">
<link itemprop="availability" href="http://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}">
<form action="/cart/add" method="post" enctype="multipart/form-data" class="product-single__form" id="AddToCartForm">
<select name="id" id="ProductSelect" class="product-single__variants">
{% for variant in product.variants %}
{% if variant.available %}
<option {% if variant == product.selected_or_first_available_variant %} selected="selected" {% endif %} data-sku="{{ variant.sku }}" value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money_with_currency }}</option>
{% else %}
<option disabled="disabled">
{{ variant.title }} - {{ 'products.product.sold_out' | t }}
</option>
{% endif %}
{% endfor %}
</select>
{% comment %}
<div class="product-single__quantity">
<label for="Quantity" class="product-single__quantity-label js-quantity-selector">{{ 'products.product.quantity' | t }}</label>
<input type="number" hidden="hidden" id="Quantity" name="quantity" value="1" min="1" class="js-quantity-selector">
</div>
{% endcomment %}
<div class="product-single__add-to-cart">
<button type="submit" name="add" id="AddToCart" class="btn">
<span id="AddToCartText">{{ 'products.product.add_to_cart' | t }}</span>
</button>
</div>
</form>
</div>
<div class="product-single__description rte" itemprop="description">
{{ product.description }}
</div>
{% if settings.social_sharing_products %}
{% include 'social-sharing' %}
{% endif %}
</div>
</div>
</div>
{% if collection %}
<hr class="hr--clear">
<div class="text-center">
← {{ 'products.general.collection_return' | t: collection: collection.title }}
</div>
{% endif %}
</div>
{% comment %}
*IMPORTANT:*
This theme uses a customized version of `option_selection.js` to support using radio inputs for color and size variants. The custom version is in `variant_selection.js`.
If you wish to enable the default dropdowns for size and color
you can change the liquid asset tag below from:
{{ 'variant_selection.js' | asset_url | script_tag }}
to
{{ 'option_selection.js' | shopify_asset_url | script_tag }}
If you use the default `option_selection.js` the labels for the dropdowns will appear outside the dropdown.
You will also need to change `.radio-wrapper` to `.selector-wrapper` below.
{% endcomment %}
{{ 'variant_selection.js' | asset_url | script_tag }}
<script>
var selectCallback = function(variant, selector) {
timber.productPage({
money_format: "{{ shop.money_format }}",
variant: variant,
selector: selector,
translations: {
addToCart : {{ 'products.product.add_to_cart' | t | json }},
soldOut : {{ 'products.product.sold_out' | t | json }},
unavailable : {{ 'products.product.unavailable' | t | json }}
}
});
};
jQuery(function($) {
new Shopify.OptionSelectors('ProductSelect', {
product: {{ product | json }},
onVariantSelected: selectCallback,
enableHistoryState: true
});
// Add label if only one product option and it isn't 'Title'. Could be 'Size'.
{% if product.options.size == 1 and product.options.first != 'Title' %}
$('.radio-wrapper:eq(0)').prepend('<label for="ProductSelect-option-0" class="single-option-radio__label">{{ product.options.first | escape }} </label>');
{% endif %}
// Hide drop-down selectors if we only have 1 variant and its title contains 'Default'.
{% if product.variants.size == 1 and product.variants.first.title contains 'Default' %}
$('.selector-wrapper').hide();
{% endif %}
});
</script>
Shopify's admin interface only allows for one product image per variant. For this reason, to do what you are trying to do isn't as easy as you are hoping. Through the Shopify API you can add metafields to products and product variants and in these metafields you can store whatever information you want -- including links to additional images. Here is a link to the documentation for the metafields on variants: https://docs.shopify.com/api/reference/product_variant
Since the admin interface doesn't really give you the ability to modify the metafields directly, you have a couple of choices:
Spend the time and energy (or money) to hook up your own management tool to the API and modify it yourself.
Purchase an app from the Shopify app store that already does this for you. Here is a link to some of these apps that should guide you in the right direction: https://apps.shopify.com/search/query?utf8=%E2%9C%93&q=variant
Either way, you'll need to come up with some sort of property name convention so you know you're dealing with images because the metafields accept whatever you feel like dropping into them.
Once you are able to define the images for your product variants, then you'll need to update the logic in your liquid/javascript to accomplish the desired functionality. You can do this a few different ways, and different people will have different opinions based on SEO but my suggestion for the path of least resistance is to do something like this:
{% for v in product.variants %}
<div id="variant_{{ v.id }}">
{% for m in v.metafields %}
{% if m.key contains "WHATEVER_CONVENTION_YOU_USED_TO_DENOTE_IMAGES" %}
{% comment %}
OUTPUT THE IMAGE TAG - PROBABLY WRAPPED IN AN ANCHOR
{% endcomment %}
{% endif %}
{% endfor %}
</div>
{% endfor %}
You'll want to incorporate some logic to show and hide the div based on the variant. Note the <div id="variant_{{ v.id }}">
The reason for this approach rather than using the api to populate js objects is that your links are already in the DOM and you can create javascript handlers when the page loads. If you wait to populate your images and links until the user selects the variant, then you'll have to deal with the event handling of dynamically created nodes.
Hope all this guides you in a good direction. If you have questions or need help feel free to reach out to me via my profile.
Additional Note: Good software developers will note the O(n^2) time complexity in the code above. Shopify doesn't execute your backend code when the page loads, rather it is executed and cached when your theme is uploaded or modified. Because of this, the poor O(n^2) time complexity won't hurt your page load performance.
As a side fun fact, this is the reason Shopify cannot create Liquid tags for things like current_time or random. Their caching mechanism which keeps sites from crashing even when being presented on Shark Tank also relies on the fact that their liquid tags, filters, and blocks don't return variable results. So, they can cache the resulting HTML and serve it directly from their caching servers...thus tags like random or current_time would only ever have an opportunity to run once.
you can try variant-image-automator paid app. this hides unnecessary images from the product page.

Categories

Resources