I have rendered the product variants as radio buttons on liquid. Now I am trying to listen to the variant change and render different prices accordingly. However, I do not know how to listen to the variant change here.
Here is my code:
<form>
{% for product_option in product.options_with_values %}
{{ product_option.name }}
{% for value in product_option.values %}
<input type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% assign current = product.selected_or_first_available_variant %}
{% endfor %}
<p>Price: {{current.price}} </p>
<input type="number" min="1">
<button type="submit">Add to Cart</button>
</form>
The price only shows for the first available variant. Even when I select different radio button options, the variant price does not update.
Welcome to stack overflow
Ideally, you probably should use some classes to use for your listeners as the page can have different radio buttons possibly even in other forms.
Below probably would get you going in the right direction.
<form>
{% for product_option in product.options_with_values %}
{{ product_option.name }}
{% for value in product_option.values %}
<input class="option" type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% assign current = product.selected_or_first_available_variant %}
{% endfor %}
<p>Price: <span id="variantPrice">{{current.price}}</span></p>
<input type="number" min="1">
<button type="submit">Add to Cart</button>
</form>
You haven't mentioned if you are using jquery or not.
I'm going to assume you are.
<script>
$( document ).ready(function() {
// Load all product data to an object
var productData = {{ product | json }};
// Listen to radio button updates and trigger a function to identify the variant
$('.option').change(function() {
idSelectedVariant();
});
function idSelectedVariant(){
//1. Loop through the options and identify the selected options
//2. Once the selected options are identified, loop through the variants in the productData object and identify the selected variant by checking the variant options
//3. Keep in mind that not all product variants are going to have 3 options all the time. Some products can have 1 or 2 options as well.
//4. Once the relevant variant is identified display the variant price by updating the content in the variantPrice span.
}
});
</script>
Related
I am rendering different groups of radio buttons for product variant options. (For example: a t-shirt can have 3 different radio button groups : size, material, color). Now I am trying to store the user selected radio button values in an array and add the product variant to the cart. I am storing the values with an onclick event on the radio buttons. But because of this, if I change my size choice from XS to S, then both of the XS and S values get added to my array. But I only need the final radio button values to be stored in my array so that I can compare it with my json data and find the variant id. Therefore, I am trying to store all the selected radio button values as an onclick event on the add to cart button, that way it will only store the final selected radio button values. However, I am not sure how to access all the radio button values from different groups in this part. Any help will be appreciated. This is my code so far:
<div class="radios">
{% for product_option in product.options_with_values %}
<p>{{ product_option.name }} -- </p>
{% for value in product_option.values %}
<input type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% endfor %}
<script>
var optionsArray = [];
var filteredOptionsArray = [];
document.querySelector('.radios').addEventListener('click', function(e) {
optionsArray.push(e.target.value);
filteredOptionsArray = optionsArray.filter(function (el) {
return el != null;
});
console.log(filteredOptionsArray);
// console.log(optionsArray.toString());
})
</script>
</div>
<div class="quantity-add">
<div class="input-quantity">
<input class="input-quantity" type="number" min="1" placeholder="1" name="quantity" value="1">
<input type="hidden" id="add-cart" name="id" data-productid="{{ product.variants[0].id }}" value="{{ product.variants[0].id }}" data-variant-title="{{ product.variants[0].title }}" />
</div>
<div class="cart-button">
<button class="cart-btn" type="submit" value="Add To Cart">ADD</button>
<!-- script for adding the selected variant to the cart -->
<script>
document.querySelector('.cart-btn').addEventListener('click', function () {
for (let i=0; i < variantsArray.length; i++) {
if ((JSON.stringify(filteredOptionsArray))== (JSON.stringify(variantsArray[i].options))) {
console.log('stringify match check works');
console.log(variantsArray[i].options);
document.querySelector('#add-cart').value = variantsArray[i].id;
}
else {
console.log('stringify match check failed');
console.log(variantsArray[i].options);
}
}
})
</script>
</div>
found it, I needed to do this:
const checkedRadios = document.querySelectorAll('input[type="radio"]:checked');
const radio_values = Array.from(checkedRadios, radio => radio.value);
I want to add another textarea to my Shopify contact form that will be sent to me when a customer emails me. The current textarea is as below:
<label for="{{ formId }}-message">Please provide further detail</label>
<textarea
class="textarea-vertical-resize-only"
rows="10"
id="{{ formId }}-message"
name="contact[{{ 'contact.form.message' | t }}]"
required="required"
>
{% if form.body %}{{ form.body }}{% endif %}</textarea
>
The issue is that it uses the variable {{ 'contact.form.message' | t }} - so I believe I need to create a new variable for another textarea input that it will capture.
What do I need to do to be able to have another unique textarea for it to capture and send to my email?
Yes you are right, your issue is with {{ 'contact.form.message' | t }}, this liquid code is a translation of an object you have in your locales -> en.default.json or any other translations.
What you are looking at is having something like this:
<label for="{{ formId }}-further-details">Please provide further detail</label>
<textarea
class="textarea-vertical-resize-only"
rows="10"
id="{{ formId }}-further-details"
name="contact[further-details]"
required="required"
>
{% if form.further-details %}{{ form.further-details }}{% endif %}
</textarea>
Notice that the name of the text area is contact[further-details] and I use the same variable "further-details" and the content {% if form.further-details %}{{ form.further-details }}{% endif %}
Hope this helps to solve your issue.
Cheers
The following flask code creates a select .. option dropdown menu:
model:
class SelectForm(Form):
country = SelectField('Country', choices=[
('us','USA'),('gb','Great Britain'),('ru','Russia')])
flask app:
#app.route('/new')
def new():
form = SelectForm()
return render_template('new.html', form = form )
html file:
<form method=post action="/register">
{{ render_field(form.country) }}
<p><input type=submit value=Register>
</form>
macro file the defines render_field:
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
What is the best way to have onchange submit the results automatically without the user having to press the submit button? Is there a way to change the macro or what's the most elegant way?
thanks
It can be done by add javascript onchange function as attribute
<form method=post action="/register">
{{ render_field(form.country(**{"onchange":"this.form.submit()"})) }}
<input type=submit value=Register>
</form>
I'm trying to port an application with an existing db. I'm using db_column to have django model Foreign Keys correctly while using the existing database names and columns.
models.py
class foo(models.Model):
foo_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_name = models.CharField(max_length=500, blank=True, null=True)
foo_type_lookup = models.ForeignKey('foo_type_lookup', to_field="foo_type_id", db_column="foo_type", blank=True, null=True)
class foo_type_lookup(models.Model):
foo_type_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_type = models.CharField(max_length=500, blank=False, null=False)
The table foo_type_lookup has two rows (ids 0 and 1) for foo_type 'bar' and 'baz'. I'm trying to make a form to add a record in the foo table which will have a foreign key to foo_type_lookup. Foo can either be bar or baz.
views.py
def add_foo(request):
action = '#'
errors = None
if request.method == 'POST':
form = FooForm(request.POST)
if form.is_valid():
form.save(commit=True)
return home(request)
else:
# The supplied form contained errors - just print them to the terminal.
errors = form.errors
else:
# If the request was not a POST, display the form to enter details.
form = FooForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'foo/add_foo.html', {'form' : form, 'errors' : errors, 'action' : action})
forms.py
CONTACT_FOO_CHOICES = [[0,'Bar'],[1,'Baz']]
class FooForm(forms.ModelForm):
foo_type_lookup = forms.ChoiceField(widget=RadioSelect(), choices=CONTACT_FOO_CHOICES)
foo_name = forms.CharField(label='First Name', max_length=500, required=False)
class Meta:
model = foo
fields = ('foo_name','foo_type_lookup')
I have to iterate over the form object in my template so I can add a jQuery function when the radio buttons are changed. I find this pretty clunky, but I'm not sure of a more django way to accomplish this:
add_foo.html
<h2>add_foo.html</h2>
<form action="{{action}}" method="post" role="form">
{% csrf_token %}
{% for field in form %}
{% if field.auto_id = 'id_foo_type_lookup' %}
{% for choice in form.foo_type_lookup.field.choices %}
<li>
<label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
<input type="radio"
id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
value="{{ choice.0 }}"
{% if choice.0 == '0' %}
checked="true"
{% endif %}
name="{{ field.html_name }}"
onchange="someFunction('id_{{ field.html_name }}_{{ forloop.counter0 }}')"/>
{{ choice.1 }}
</label>
</li>
{% endfor %}
{% else %}
<div class="formfield_err">{{ field.help_text }}</div>
<div id="{{ field.auto_id }}_container" >
<div class="formfield_divlbl">{{ field.label_tag }}
</div>
<div class="formfield_divfld">{{ field }}
{% if field.field.required %}
<span class="required">*</span>
{% endif %}
</div>
<div id="{{ field.auto_id }}_errors">{{ field.errors }}
</div>
</div><div class="clear" style="margin-bottom:12px;"></div>
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
I get the error:
Cannot assign "'0'": "foo.foo_type_lookup" must be a "foo_type_lookup" instance.
How do I layout the radio buttons for the type lookup to add onchange javascript and supply my ModelForm with an object of 'foo_type_lookup' so the data will save to the database?
A ChoiceField does not know it needs to coerce the provided value to a particular model instance.
Use a ModelChoiceField instead.
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield
Whoops, it seems you want some very specific display logic for your values hard coded into your python which may not necessarily equate to your string representations of your related model.
If so, override your form save to apply any coercion there before the real save gets called via super.
You can also manually apply any python logic via commit=False (I notice you already have that statement set to True and perhaps you were playing with the idea.)
obj = form.save(commit=false)
obj.foo_lookup_type = MyObject.objects.get(pk=form.cleaned_data['foo_lookup_type'])
obj.save()
I have this code of HTML (Django + Jinja) .
<div class="span10 well">
{% for k in values.chat %}
<label> Text : {{k.text}} </label>
<label> {{k.date_time}} </label>
{% endfor %}
<form action = "#" method = "POST" id = {{key}} name = "reply_form">
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "Sent" class="btn btn-primary">
</form>
</div>
Since, there will be many chats and correspondingly reply submit button and its key, I want that when I reply to a specific chat, it carries the key with itself and process the chat accordingly.
What I need is to append the url with the form id parameter. How can I achieve this?
You can create a hidden input field
<input type="hidden" name="chat_key" value="{{key}}">
This way you can track which chatroom the person is responding by setting the value to the id of the chatroom.
EDIT: Since you are using django, on the backend to get the value of the chat_key you can just do this:
chat_key = form.cleaned_data['chat_key']