Shopify validation for custom attribute fields in cart page - javascript

We have a Shopify website (Dawn theme) and we added some custom attribute fields on cart page which is associated with the product added to cart.
For showing the attribute fields, below is the code I'm using in the cart page file:
{% for variable in (1..item.quantity) %}
<div class="user_web_info">
<div class="cart-attribute__field">
<label for="website-name{{variable}}">Website Name*</label>
{% capture attributename %}Website Name{{variable}}{% endcapture %}
<input type="text" aria-required="true" required="required" class="required" data-name="Website Name{{variable}}" id="website-name{{variable}}" name="attributes[Website Name{{variable}}]" value="{{ cart.attributes[attributename] }}">
</div>
<div class="cart-attribute__field">
<label for="website-url{{variable}}">Website URL*</label>
{% capture attributeurl %}Website URL{{variable}}{% endcapture %}
<input type="text" aria-required="true" required="required" class="required" data-name="Website URL{{variable}}" id="website-url{{variable}}" name="attributes[Website URL{{variable}}]" value="{{ cart.attributes[attributeurl] }}">
</div>
</div>
{% endfor %}
I got the code for fields from this article:
https://community.shopify.com/c/online-store-2-0/dawn-theme-add-custom-fields-in-cart-page-and-show-results-in/td-p/1410437
I'm facing an issue with the validation of these fields when clicking checkout button on the cart page. Default HTML validation is showing in the field when clicking checkout without filling the fields, but the user is immediately redirecting to checkout page after that.
I tried to use simple jquery / javascript code as mentioned in these articles for preventing the form submission when validation happens. But it is not working:
https://community.shopify.com/c/technical-q-a/how-to-prevent-login-form-submit/td-p/1787161
https://community.shopify.com/c/shopify-apis-and-sdks/help-needed-validation-function-for-add-to-cart-form-submission/td-p/261161
I implemented the validation code in a separate js file and included it in theme.liquid file.
I searched a lot for finding a solution, but couldn't find it yet. I even used an App here: https://apps.shopify.com/customized-attribute
I need the validation for the checkbox also.

I figured out the issue here
I changed the checkout button from type="submit" to type="button" and changed the name attribute of checkout button to "checkout1". I'm not sure how these things affecting the form submission, but i had to do these.
Then I commented out these default form submission code in the cart page footer file:
document.querySelector('#checkout').addEventListener('click', function(event) {
document.querySelector('#cart').submit();
});
Also implemented the below validation code in custom js file:
document.querySelector('#checkout').addEventListener('click', function(event) {
event.preventDefault();
let errors = 0;
document.querySelectorAll('input.required').forEach((input) => {
let val = input.value;
console.info(val.length);
if(val.length == 0){
errors = errors + 1;
}
});
if(errors > 0){
alert("Please fill all the required fields.");
return false;
}
else if(!document.querySelector('#disclmr-chk').checked) {
alert("Please check the checkbox.");
return false;
}else{
document.querySelector('#checkout').setAttribute('name', 'checkout');
document.querySelector('form#cart').submit(); }});

Related

Refresh (variable) part of an html page with hotwire (Flask app)

Context
I am building a simple "todo" flask app with an SQLAchemy database.
The tasks are sorted by sections (check the image below to see how it is organized).
Once I implemented all the functionalities I wanted, I ran into the issue which was the whole page
got refreshed each time I triggered a button (add/edit/delete/update_status).
Then I found out hotwire which is amazing to handle this.
This my taskManager.html organization:
<!--New task button-->
<turbo-frame id="data_frame-add">
<button class="btn-add" onclick="openAddForm()">...</button>
<div class="form-popup" id="myForm">
<form name="AddTaskForm" action="{{ url_for('add_task') }}" class="form-container" method="POST">
<label for="section"><b>Section</b></label>
<input type="text" id="section" name="section" required>
<label for="content"><b>Task</b></label>
<input type="text" id="content" name="content required>
<button type="submit" class="btn">Add</button>
</form>
</div>
</turbo-frame>
<!--Display sections and tasks-->
<div class="flex-row">
{% for section in sections %}
<turbo-frame id="data_frame-{{ section }}">
<div class="flex-column">
<h2>{{ section }}</h2>
{% for task in tasks %}
{% if task.section == section %}
<p>{{ task }}</p>
<button class="satus"></button>
<button class="edit"></button>
<div class="form-popup" id="form-{{ task.id }}">...</div>
<button class="delete"></button>
<div class="form-popup" id="form-{{ task.id }}">...</div>
{% endif %}
{% endfor %}
</div>
</turbo-frame>
{% endfor %}
</div>
Using a turbo frame with id data_frame-{{ section }} (one for each section) allowed to refresh only the concerned section when hitting status, edit and delete buttons (for example, hitting delete button of task 2 of Section 2 will only refresh the turbo frame data_frame-Section 2). However as the New task button is out of theses turbo frames, It works differently and this is a different challenge...
Issue
When adding a new task, I would like the section of the task (entered here <input type="text" id="section" name="section"...>) to be saved in a variable which will be used to target a specific <turbo-frame id="data_frame-{{ section }}"> and refresh it without refreshing the whole page.
At the moment as the New task button is wrapped with <turbo-frame id="data_frame-add"> it is self contained (meaning if I'm adding a task 5 to Section 1 only the turbo frame with id data_frame-add is refreshed not the data_frame-Section 1 so I need to manually refresh the page to see changes)
What I tried
I added data-turbo-frame to the form:
<form name="AddTaskForm" action="{{ url_for('add_task') }}" class="form-container" method="POST" data-turbo-frame="data_frame-Section 1">
in order to be able to refresh the "data_frame-Section 1" when I add a New task in section Section 1, and it works! But I would like to make this data-turbo-frame="data_frame-<section>" with <section> a variable that get the value of <input type="text" id="section" name="section"...>
To achieve this I removed data-turbo-frame="data_frame-Section 1" in the form:
<form name="AddTaskForm" action="{{ url_for('add_task') }}" class="form-container" method="POST">
and added a Javascript part:
var sectionValVar = document.getElementById("section").value;
const sectionValPref = "data_frame-";
let sectionVal = sectionValPref + sectionValVar;
$(".AddTaskForm").attr("data-turbo-frame", sectionVal);
sectionVal is supposed to get the variable value "data_frame-<section>" and last line add "data-turbo-frame" = "data_frame-<section>" to the <form name="AddTaskForm"...>
But this doesn't work. I'm not sure if this even possible to make as it looks tricky...
But if someone has any hint or fix for this It would be amazing !
Thank you !
Other ressources
This is my add_task route in my python flask app:
#app.route('/add', methods=['GET', 'POST'])
def add_task():
content = request.form.get('content')
section = request.form.get('section')
task = Task(content=content, section=section)
db.session.add(task)
db.session.commit()
return redirect(url_for('taskManager'))
This looks like it would work but I don't see an event listener to set the form data-turbo-frame attribute whenever the input value changes.
You need to update the attribute either before the form submits or whenever the input gets updated.
this is how you could do it with jquery
$("#section").change(function() {
let sectionAndPrefix = "data_frame-" + $("#section").val()
$(".AddTaskForm").attr("data-turbo-frame", sectionAndPrefix);
})
in vanilla javascript
const sectionInput = document.querySelector("#section")
sectionInput.addEventListener("input", function() {
const taskForm = document.querySelector(".AddTaskForm")
const sectionAndPrefix = "data_frame-" + sectionInput.value
taskForm.setAttribute("data-turbo-frame", sectionAndPrefix)
})

Dynamically added input fields aren't being submitted in request.form

I have a form in my input.html page and I have a set of input fields that is both programmatically generated by jinja2 and dynamically generated with Javascript. The inputs that are generated by jinja2 all show up in my request.form when I hit submit (i.e. into my POST function), but the dynamically created fields (with the + button next to a given element) aren't showing up. Which is strange, because if I inspect the page after adding a few new inputs, they... should?
Any ideas?
HTML
(explanation: this iterates through a ~dict and x has two text fields called question and tech-key (ex// "int"). This should print out the question with a 'plus sign' to allow the user to add new input fields dynamically. I include one by default (ex// name="{{x['tech_key']}}1" means name="int1". Every new input field that gets added increments (int1, int2, int3, etc...)
<div class="col-md-9">
{% for k,v in inps['sheet'].items() %}
{% for x in v %}
<div class="{{x['tech_key']}}">
<b>{{x['question']}}</b>
<button class="add_form_field" data-key="{{x['tech_key']}}"><b>+</b></button><br>
<div><input type="text" name="{{x['tech_key']}}1" size="80px"></div>
</div>
{% endfor %}
{% endfor %}
</div><br>
JavaScript
(explanation: This allows me for each individual named div (ex: the <div class="int"> above), to add new input fields when I click the + sign next to my product. I have them connected to the original form. They aren't pushing when I hit submit.
// adds new input fields when the + is clicked on a given question
$(document).ready(function() {
var max_fields = 10;
var add_button = $(".add_form_field");
var x = 1;
$(add_button).click(function(e){
use = $(this).attr("data-key")
var wrapper = "."+use
e.preventDefault();
if(x < max_fields){
x++;
var field_name = use + x
$(wrapper).append('<div><br><input type="text" form="input_form" name="'+field_name+'"/ size=80px><a class="'+field_name+'"><button><b>-</b></button></a></div>'); //add input box
}
$("."+field_name).click(function(){
$(this).closest('div').remove(); x--;
})
});
});
HTML copied directly from my page when I add two new input fields:
<div class="int">
<b>Did you conduct any interviews this quarter?</b>
<button class="add_form_field" data-key="int" data-ol-has-click-handler=""><b>+</b></button>
<div>
<br><input type="text" name="int1" size="80px">
</div>
<div>
<br><input type="text" form="input_form" name="int2" size="80px">
<a class="int2"><button><b>-</b></button></a>
</div>
<div>
<br><input type="text" form="input_form" name="int3" size="80px">
<a class="int3"><button><b>-</b></button></a>
</div>
</div>

Colorbox + Form, Submit only working on Enter button (not onclick)

I integrated a popup upon landing on our page http://www.showstye.lu (best seen in an incognito window due to cookie reset). In this popup you have a newsletter signup form which is a copy of the one available in the footer.
I had to duplicate css to adapt to the newsletter popup so that it styled correctly which is fine, I am using Colorbox for the popup itself.
Now, the form itself when I click on the submit button (S'Abonner) it doesn't trigger the submit correctly. I always get a false return telling me to resubmit a new e-mail address.
However, the newsletter form itself works completely fine in the footer and ALSO when I use the keyboard stroke "Enter" instead of clicking on the submit button.
I don't comprehend why one form works in the footer but the identical copy does not (only with Enter keystroke), I looked at the styling/JS/html of the form and it is identical across both.
Any ideas how to resolve this so that the submit button works successfully?
<div style='display:none'>
<div id='subscribe_popup'>
<div id="spop_left">
<div id="spop_top"></div>
<div id="spop_sign">
<div class="popbox">
{% if theme.setting_newsletter %}
<form id="formNewsletter" action="{{ 'account/newsletter' | url }}" method="post">
<input type="hidden" name="key" value="{{ page.key }}" />
<input type="email" name="email" id="formNewsletterEmail" value="" placeholder="{{ 'E-mail' | t }}"/>
<a class="btn glyphicon glyphicon-send" href="#" onclick="$('#formNewsletter').submit(); return false;" title="{{ 'Subscribe' | t }}" {% if shop.language == 'de' %}style="padding: 0px 10px;"{% endif %}><span>{{ 'Subscribe' | t }}</span></a>
</form>
</div> {% endif %}
</div>
</div>
<div id="spop_right"></div>
</div>
</div>
<!-- END subscribe popup-->
Here is the JS behind it:
<script> // popup script
$("document").ready(function (){
// load the overlay
if (document.cookie.indexOf('visited=true') == -1) {
var fifteenDays = 1000*60*60*24*15;
var expires = new Date((new Date()).valueOf() + fifteenDays);
document.cookie = "visited=true;expires=" + expires.toUTCString();
$.colorbox({width:"553px", inline:true, href:"#subscribe_popup"});
}
$(".open_popup").colorbox({width:"553px", inline:true, href:"#subscribe_popup"});
});
</script>
Ok that was it, I was integrating a submit into the hyperlink instead of using a simple inputtype submit, keystroke was obviously working because of how the browser automatically identifies the keystroke enter as a submit!

Javascript Confirm continues regardless of user answer

I have an html template that I use with my Django website code. In the template are a couple of forms. Two of the forms are datefields and I have a confirm popup that is activated on submission if the user fills them in. I wanted the popup to exit the form submission and return to the page if the user clicks 'cancel', and to continue submitting the form if the user clicks 'ok'.
The confirm popup shows up correctly but the form submission continues no matter what the user clicks. How do I change it so that the form submission exits if the user clicks 'cancel'?
Javascript looks like this:
<script type="text/javascript">
var checkFields = ["SPAN_START","SPAN_END"];
function checkForm( theForm ) {
for (i in checkFields ) {
var fieldName = checkFields[ i ];
var theField = theForm[ fieldName ];
if ( theField.value ) {
var retVal = confirm("Are you sure you want to specify a date?");
if (retVal == true){
theField.submit()
return true;
} else {
return false;
}
}
}
}
</script>
The html where it is used looks like this:
<form action="/InterfaceApp/Nominal_Request/" method="post" class="form" onsubmit="checkForm( this )">
{% csrf_token %}
<div class="panel-body text-center">
{% bootstrap_form form_span_start %}
{% bootstrap_form form_span_end %}
{% buttons %}
<button type="submit" class="btn btn-primary center-block" value="Submit" name="Range">
{% bootstrap_icon "fire" %} Generate Range of Requests
</button>
{% endbuttons %}
</div>
</form>
Can anyone tell me how to cancel the submission of the form if the user clicks 'cancel'??
Much appreciated.
You have to return the value of the function to the inline event handler
onsubmit="return checkForm( this )"
preferably you wouldn't use inline event handlers at all, but addEventListener instead.

Retain textbox value on return to same button

The question look quite confusing but here is what i need, I use snipe IT ams application which is built on laravel framework.
I have a html page with a textbox and two radio button namely automatic and manual when user clicks on automatic button a php function is called and a random number is generated and the textbox field will become disabled on the other hand whenever a user clicks the manual button the textbox field must become enabled and the user can enter a value in the textbox field.
<script>
function CreateRandomNumber()
{
$('#asset_number').attr('value',("<?php CreateRandomNumber(); ?>"));
$('#asset_number').attr('disabled','disabled');
}
function EnableManualTextfield()
{
$('#asset_number').removeAttr('disabled');
$('#asset_number').val("");
}
</script>
<div class="form-group {{ $errors->has('asset_number') ? ' has-error' : '' }}">
<label for="asset_number" class="col-md-3 control-label">#lang('admin/assetdetails/form.number')</label>
<div class="controls col-md-7">
<input class="form-control assettext" type="text" name="asset_number" id="asset_number" value="{{ Input::old('asset_number', $assetdetail->asset_number) }}" />
{{ $errors->first('asset_number', '<span class="alert-msg"><i class="icon-remove-sign"></i> :message</span>') }}
<input class="radio-button" type="radio" id="automatic" name="asset" onclick="CreateRandomNumber()" value="{{ Input::old('automatic',$assetdetail->automatic) }}" class="align-check1">
<label for="automatic" class="control-label">#lang('admin/assetdetails/form.auto')</label>
<input class="radio-button align-check2 manualradio" type="radio" id="manual" name="asset" onclick="EnableManualTextfield()" checked="checked" value="{{ Input::old('manual',$assetdetail->manual) }}">
<label for="manual" class="manualtext">#lang('admin/assetdetails/form.manual')</label>
</div>
</div>
/* CreateRandomNumber Function */
/* This function is written seperately in a php file */
<?php
function CreateRandomNumber() {
$letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$numbers = rand(100, 999999);
$prefix = "SS-";
$randomNumber = $prefix . $numbers ;
echo $randomNumber;
}
?>
Now the problem is whenever a user clicks on automatic a number is getting generated and if returned back to manual the text field gets enabled as expected, but i need do design it in such a way that if the user return backs to automatic button the pre-generated number must be display in the textfield.
Please note that the form is not yet submitted i need to store the generated random number in a variable and get the same number back when gets backs to the automatic field i do know how to achieve this please help me i am new to php and laravel.
Value is not an attribute, so you have to change
$('#asset_number').attr('value',("<?php CreateRandomNumber(); ?>"));
into
$('#asset_number').val("<?php CreateRandomNumber(); ?>");

Categories