Avoid user click submit button more than once? - javascript

I'm working on a asp.net MVC project. On one page, it has many controls and features. When user clicks 'submit' button, it will do many validations in the controller for the input. If something is not right, it will show the error on the page. Otherwise, will save the data in the database with a Guid, and go to the next page.
The problem is: the validation takes some time, user may accidentally click the submit button more than once which results in saving data to the database with the same Guid, which throws an error since Guid has to be unique for each data.
Is there a way to prevent user clicking more than once? We can not simply disable the button after click. If the validation has issue, then user can not submit again since the button is disabled.

You can disable the submit button until all the validation has been completed. Track a variable for each conditional that returns true when the validation for that section of the form is complete and then check each of these variables at the end to make sure each one is true. If they are all true set the submit.disabled to false.
NOTE: You can do this with each input as well, disabling each input until the previous input has been properly validated.
Below is a very rudimentary example of this logic.
const submit = document.getElementById('submit')
const fname = document.getElementById('fname')
const lname = document.getElementById('lname')
const email = document.getElementById('email')
const inputs = document.querySelectorAll('.input')
function emailIsValid(email) {
return /^[^\s#]+#[^\s#]+\.[^\s#]+$/.test(email)
}
function nameIsValid(name) {
return name.match(/^[A-Za-z]+$/)
}
function validate(fname, lname, email, submit) {
// the validation variables to check at end to set submit.disabled to false
let fnameCheck = false,
lnameCheck = false,
emailCheck = false;
// check first name field
if (fname.value !== '' && fname.value.length > 1 && nameIsValid(fname.value)) {
fname.style.background = 'lightgreen'
fname.previousSibling.previousSibling.style.background = 'green'
fnameCheck = true
} else {
// JIC they delete reset to false
fnameCheck = false
fname.style.background = 'pink'
}
if (lname.value !== '' && lname.value.length > 2 && nameIsValid(fname.value)) {
lnameCheck = true
lname.style.background = 'lightgreen'
} else {
lnameCheck = false
lname.style.background = 'pink'
}
if (emailIsValid(email.value)) {
emailCheck = true
email.style.background = 'lightgreen'
} else {
emailCheck = false
email.style.background = 'pink'
}
// log for visual inspection of check-variable values
console.log(lnameCheck, fnameCheck, emailCheck)
// make sure all check-variables are set to true
if (fnameCheck === true && lnameCheck === true && emailCheck === true) {
submit.disabled = false
}
}
// event listener for each input on input field run the validate function
// and pass in our inputs and submit button for manipulation.
inputs.forEach(input =>
input.addEventListener('input', () => validate(fname, lname, email, submit))
)
<form action="#">
<label for="fname">First name:</label><br>
<input type="text" id="fname" name="fname" class="input"><br>
<label for="lname">Last name:</label><br>
<input type="text" id="lname" name="lname" class="input"><br>
<label for="email">email:</label><br>
<input type="text" id="email" name="email" class="input"><br>
<input type="submit" id="submit" value="Submit" disabled>
</form>

Related

onBlur causes infinite loop of alert messages in Chrome

I have to make a HTML page, with a form containing an email address and a URL. I should check whether the email is a legitimate Gmail or Yahoo! format, and if the URL is correct as well. However, on Chrome, when I type a wrong email, then without correcting it I click into the URL's input, I get infinite alert messages.
Here's the HTML file
<form action="/index.html" method="POST" name="form">
<p>Full name: <input type="text" pattern="[A-Z][a-z]+ [A-Z][a-z]+"></p>
<p>Date: <input type="date"></p>
<p>Email: <input type="email" id="email" onblur="validateEmail(document)"></p>
<p>Favourite website: <input type="url" id="url" onblur="validateFavURL(document)"></p>
</form>
And heres the JS file:
function validateEmail(document) {
let email = document.getElementById("email").value
let regexGmail = /\S+#gmail\.\S+/
let regexYahoo = /\S+#yahoo\.\S+/
if (!regexGmail.test(email) || regexYahoo.test(email)) {
alert("Incorrect email address!")
}
}
function validateFavURL(document) {
let url = document.getElementById("url").value
let regexURL = /https?:\/\/www\.[A-Za-z1-9_-]+\.[A-Za-z1-9_-]+\.[A-Za-z1-9_-]+/
let regextwodots = /^((?!\.\.).)+/
let regexdots = /\..+\./
if (!regexURL.test(url) || !regextwodots.test(url) || regexdots.test(url)) {
alert("Incorrect webpage!")
}
}
I have changed some of your code and added some of mine, now the alert will be triggered with smart.
/*
hasAlreadyAlerted is a boolean variable, from it's name you know that
this variable will be false only if the elementy currently focusing on
has not been alerted last time.
alwertedElement is a reference to the last element that triggered the alert
*/
var hasAlreadyAlerted = false, alertedElement;
document.querySelector("form").addEventListener('focus', (event) =>
hasAlreadyAlerted = event.target == alertedElement, true);
function validateEmail(emailElement) {
let email = emailElement.value,
regexGmail = /\S+#gmail\.\S+/,
regexYahoo = /\S+#yahoo\.\S+/;
if(!hasAlreadyAlerted && (!regexGmail.test(email) || regexYahoo.test(email))) {
hasAlreadyAlerted = true;
alertedElement = emailElement;
alert("Incorrect email address!")
}
}
function validateFavURL(urlElement) {
let url = urlElement.value,
regexURL = /https?:\/\/www\.[A-Za-z1-9_-]+\.[A-Za-z1-9_-]+\.[A-Za-z1-9_-]+/,
regextwodots = /^((?!\.\.).)+/,
regexdots = /\..+\./;
if (!hasAlreadyAlerted && (!regexURL.test(url) || !regextwodots.test(url) || regexdots.test(url))) {
hasAlreadyAlerted = true;
alertedElement = document.getElementById("url");
alert("Incorrect webpage!")
}
}
/*
So if the user types a wrong email or url that triggers the alert and
stores the reference of the element and that an alert has already triggerd,
and no other alerts should be triggered from the same element unless the user
has clicked in another one, this is all to avoid getting in an infinite loop
like you have already seen, and the cause of that loop is just the way the
events are being handled, I thinks when the user types something and clicks
outside the input element the blur event is triggered and that triggers an
alert and once you click on the alert button the blur event is triggered once
again and so on making a an infinite number of alerts
*/
<form action="/index.html" method="POST" name="form">
<p>Full name: <input type="text" pattern="[A-Z][a-z]+ [A-Z][a-z]+"></p>
<p>Dátum: <input type="date"></p>
<p>Email: <input type="email" id="email" onblur="validateEmail(this)"></p>
<p>Kedvenc weboldal: <input type="url" id="url" onblur="validateFavURL(this)"></p>
</form>

How to solve blur and submit event simultaneous in angular

I have text box in my page, which i can enter 9 digit number. Onblur I am validating like the entered number is valid or not using API call, If service returns failure it will clear the text box with red border and form will be invalid. The event conflict happening between OnBlur and Submit. Submit service will call only the form is valid otherwise it will show toaster like enter mandatory filed.
If the text field focused and directly if I click on submit button, both event calling simultaneously and it is clearing the number field OnBlur as well as the service is calling.
Please can you help me to resolve this conflicts.
file.html
<form class="contact-form" #create="ngForm">
<div class="controls">
<input NumberOnly="true" type="text" id="num" [ngClass]="{'red-border-class': ((showErrorFlag == true && numberField.errors) || (showErrorFlag == true && numberField.errors && (numberField.dirty || numberField.touched)))}"
[disabled]="disableRotaDetailFields" [(ngModel)]="number"
class="floatLabel" name="ownership" required #numberField="ngModel" (blur)="validatenumber(number)" [maxLength]="einLength">
<label for="ein">number<sup>*</sup></label>
</div>
<button (click)="SaveData(create)">Save</button>
</form>
file.ts
public validatenumber(number) {
let reqObj = {
"ownership": number
}
this.calloutService.validateOwnerEin(reqObj)
.pipe(takeUntil(this.unsubscribe))
.subscribe((data) => {
}, (err) => {
if (err.status == 404) {
this.number = "";
}
this.toastr.error(err.overriddenMessage);
})
}
SaveData(){
if (!formFlag.valid ) {
this.showErrorFlag = true;
this.toastr.error('Please fill all the mandatory fields');
}else {
this.calloutService.createData(this.data)
.pipe(takeUntil(this.unsubscribe))
.subscribe(data => {
this.showSpinnerFlag = false;
let response = data;
if (data) {
this.toastr.success("Rota created successfully.");
} else {
this.toastr.error("Could not save.");
}
}, err => {
this.showSpinnerFlag = false;
this.toastr.error(err.overriddenMessage);
})
}
}

jQuery to show/hide required password field

I have a form to change the personal details of the user. In this form I allow the user to change their email and/or password. With jQuery I want to show a 'Current Password' field when it detects that one of these fields is changed.
For the email field this means that when it is changed the password field appears, but when the email is re-entered correctly it hides itself again.
For the password field this means it simply shows when anything is typed inside the field.
I got the basics working, but I can't get them to work with each other. So when I change both and change one back, the Current Password field hides itself.
let requiredSet;
$('.js-show-target-on-change').on('input', function() {
const target = $('.js-show-target-on-change__target');
let currentValue = $(this).val();
if ( $(this).data('type') === 'email' ) {
const emailValue = $(this).data('value');
if ( currentValue !== emailValue && !requiredSet === true ) {
target.show();
target.find('input').prop('required', true);
requiredSet = true;
} else if ( currentValue === emailValue ) {
target.hide();
target.find('input').prop('required', false);
requiredSet = false;
}
} else {
if ( !requiredSet === true ) {
target.show();
target.find('input').prop('required', true);
requiredSet = true;
} else if ( !currentValue.length ) {
target.hide();
target.find('input').prop('required', false);
requiredSet = false;
}
}
});
JsFiddle
Would love some help with this since I've been stuck for so long... Thanks in advance!
EDIT: Here's a description of how the code works:
cost email = $('#email').val() // get the starting value of the email
// field to check if it has changed
$('.js-show-target-on-change').on('input', function(){
const f = $('#email').val() !== email
// check if the old email value is different than the new email value
|| $('#newPassword').val().length > 0
// check if there is text in the new password field
? 'show' : 'hide';
// if one of the above statements are true,show the field, else hide it
$('.js-show-target-on-change__target')[f]();
// update the field based on the above condition
});
If I understood your use case correctly the following code should do the job:
const email = $('#email').val();
$('.js-show-target-on-change').on('input', function() {
const f = $('#email').val() !== email || $('#newPassword').val().length > 0 ? 'show' : 'hide';
$('.js-show-target-on-change__target')[f]();
});
Use an attribute to specify the input value has been changed and later use that attribute to toggle the visibility of the input element.
$('.js-show-target-on-change').on('input', function() {
const target = $('.js-show-target-on-change__target');
let currentValue = this.value;
// if input is email
if (this.id === 'email') {
// get default value
let defValue = $(this).data('value');
// set attribute value based on old and default value
$(this).attr('data-changed', defValue !== currentValue);
} else {
// if password field then set attribute based on length
$(this).attr('data-changed', currentValue.length > 0);
}
// check number of changed fields
let visible = $('input[data-changed="true"]').length > 0;
// toggle based on the value
target.toggle(visible);
target.find('input').prop('required', visible);
});
$('.js-show-target-on-change').on('input', function() {
const target = $('.js-show-target-on-change__target');
let currentValue = this.value;
// if input is email
if (this.id === 'email') {
// get default value
let defValue = $(this).data('value');
// set attribute value based on old and default value
$(this).attr('data-changed', defValue !== currentValue);
} else {
// if password field then set attribute based on length
$(this).attr('data-changed', currentValue.length > 0);
}
// check number of changed fields
let visible = $('input[data-changed="true"]').length > 0;
// toggle based on the value
target.toggle(visible);
target.find('input').prop('required', visible);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="post" accept-charset="UTF-8" enctype="multipart/form-data" class="c-form">
<div class="c-form__row">
<label class="c-form__label" for="email">Email</label>
<div class="c-form__field">
<div class="c-input__control">
<input required class="c-input js-show-target-on-change" data-type="email" type="email" id="email" name="email" value="info#johndoe.com" data-value="info#johndoe.com">
</div>
</div>
</div>
<div class="c-form__row">
<label class="c-form__label" for="newPassword">New password</label>
<div class="c-form__field">
<div class="c-input__control">
<input class="c-input js-show-target-on-change" type="password" id="newPassword" name="newPassword">
</div>
</div>
</div>
<div class="c-form__row js-show-target-on-change__target" style="display: none;">
<label class="c-form__label" for="currentPassword">
Current password
<span class="u-warning">(required to change email or password)</span>
</label>
<div class="c-form__field">
<div class="c-input__control">
<input class="c-input" type="password" id="currentPassword" name="password">
</div>
</div>
</div>
<div class="c-form__submit">
<button class="c-button c-button--fullwidth" type="submit">Save</button>
</div>
</form>

How trigger validation on a textbox when a button is pressed?

I've got two text boxes for first and last name. I also have a button to save the data. The button has an event handler where it grabs the data from the fields and posts them with an ajax call to my API, using jquery.
I want validation on my two textboxes (so they can't be left blank), but I don't know how to trigger that when my button is pressed. I am not using the <form> tag for this; I'm doing an ajax call when the button is pressed.
Here is an example which may help you:
$('#save').click(function() {
var errors = [];
var name = $('#name').val();
var vorname = $('#vorname').val();
if (!name) {
errors.push("Name can't be left blank");
}
if (!vorname) {
errors.push("Vorname can't be left blank");
}
if (errors.length == 0) {
console.log('Ajax started');
//put here your ajax function
} else {
for (var i in errors) {
console.log(errors[i]);
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input placeholder="Name" id="name"><br>
<input placeholder="Vorname" id="vorname"><br>
<button id="save">Save</button>
here is an example using the popular add on jquery validate. https://jqueryvalidation.org/
click the run snippet button below
$(document).ready(function() {
$("#form").validate({
rules: {
"firstname": {
required: true,
},
"lastname": {
required: true,
}
},
messages: {
"firstname": {
required: "Please, enter a first name"
},
"lastname": {
required: "Please, enter a last name"
},
},
submitHandler: function(form) { // for demo
alert('valid form submitted'); // for demo
return false; // for demo
}
});
});
body {
padding: 20px;
}
label {
display: block;
}
input.error {
border: 1px solid red;
}
label.error {
font-weight: normal;
color: red;
}
button {
display: block;
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.0/jquery.validate.min.js"></script>
<form id="form" method="post" action="#">
<label for="firstname">First Name</label>
<input type="text" name="firstname" id="firstname" />
<label for="lastname">Last Name</label>
<input type="text" name="lastname" id="lastname" />
<button type="submit">Submit</button>
</form>
Without seeing your code, it is very difficult to guess the correct scenario to provide examples for.
Given the following HTML:
<form>
<input type="text" class="text1">
<input type="text" class="text2">
<button type="button">Send</button>
</form>
You could use this for the jQuery part:
$('button').click(function() {
var txt1 = $(this).siblings('.text1').val();
var txt2 = $(this).siblings('.text2').val();
if (txt1.length && txt2.length) {
// do your ajaxy stuff here
} else {
alert("Imput some friggin' text!");
}
});
$(this) selects the button clicked.
.siblings('.text1') selects the input with class text1 inside the same block as the clicked button.
https://jsfiddle.net/sg1x0c3q/7/
As per my comments I would recommend using a form. But if you want a pure JS solution here you go. (if you want a form based solution just ask)
// convert all textareas into key value pairs (You can change the selector to be specific to your markup)
const createPayload = () => {
return [].slice.call(document.querySelectorAll('textarea')).reduce((collection, textarea) => ({
...collection,
[textarea.name]: textarea.value
}), {})
}
// Compare Object values against values that are not falsy (you could update the filter with a RegExp if you wanted more complicated validation)
const objectHasAllValues = obj => {
return Object.values(obj).length == Object.values(obj).filter(value => value).length
}
// If all key value pairs are not falsy then submit
window.submit = () => {
const payload = createPayload()
if (objectHasAllValues(payload)) {
fetch('/your/api', payload)
}
}
This solution presumes that your API expects a JSON payload. If you are expecting to send form data then you would need to use the formData js api.
This scales and doesn't need jQuery :)
Working example here https://jsfiddle.net/stwilz/dxg29mkj/28/
I want validation on my two textboxes (so they can't be left blank), but I don't know how to trigger that when my button is pressed. I am not using the <form> tag for this; I'm doing an ajax call when the button is pressed.
Answer to form validation. I assume that First name and Last name can only contain alphabets ,i.e., only a-z and A-Z.
//This function will trim extra whitespaces form input.
function trimInput(element){
$(element).val($(element).val().replace(/\s+/g, " ").trim());
}
//This function will check if the name is empty
function isEmpty(s){
var valid = /\S+/.test(s);
return valid;
}
//This function will validate name.
function isName(name){
var valid = /^[a-zA-Z]*$/.test(name);
return valid;
}
$('#myForm').submit(function(e){
e.preventDefault();
var fname = $(this).find('input[name="fname"]');
var lname = $(this).find('input[name="lname"]');
var flag = true;
trimInput(fname);
trimInput(lname);
if(isEmpty($(fname).val()) === false || isName($(fname).val()) === false){
alert("First name is invalid.");
flag = false;
}
if(isEmpty($(lname).val()) === false || isName($(lname).val()) === false){
alert("Last name is invalid.");
flag = false;
}
if(flag){
alert("Everything is Okay");
//Code to POST form data goes here...
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form name="myform" id="myForm" method="post" action="#">
<input type="text" name="fname" placeholder="Firstname">
<input type="text" name="lname" placeholder="Last Name">
<input type="submit" name="submit" value="Submit">
</form>
I am not using the <form> tag for this.
Then the code will be like
//This function will trim extra whitespaces form input.
function trimInput(element) {
$(element).val($(element).val().replace(/\s+/g, " ").trim());
}
//This function will check if the name is empty
function isEmpty(s) {
var valid = /\S+/.test(s);
return valid;
}
//This function will validate name.
function isName(name) {
var valid = /^[a-zA-Z]*$/.test(name);
return valid;
}
$('#submit').click(function() {
var fname = $('#fname');
var lname = $('#lname');
var flag = true;
trimInput(fname);
trimInput(lname);
if (isEmpty($(fname).val()) === false || isName($(fname).val()) === false) {
alert("First name is invalid.");
flag = false;
}
if (isEmpty($(lname).val()) === false || isName($(lname).val()) === false) {
alert("Last name is invalid.");
flag = false;
}
if (flag) {
alert("Everything is Okay");
//Code to POST form data goes here...
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="fname" name="fname" placeholder="Firstname">
<input type="text" id="lname" name="lname" placeholder="Last Name">
<button type="button" id="submit" name="submit">Submit</button>
Check the code on jsFiddle.
Hope this will be helpful.

Can't submit form through javascript to php

I have a form in html which I want to run verification in Javascript first before POST ing to PHP. However the link up to the PHP section does not seem to be working despite the fact that I have assigned names to each input tag and specified an action attribute in the form tag.
Here is the HTML code for the form:
<form id="signupform" action="signupform.php" method="post">
<input type="text" name="Email" placeholder="Email Address" class="signupinput" id="email" />
<br />
<input type="password" name="Password" placeholder="Password" class="signupinput" id="passwordone" />
<br />
<input type="password" placeholder="Repeat Password" class="signupinput" id="passwordtwo" />
<br />
<input type="button" value="Sign Up" class="signupinput" onClick="verifypass()" id="submit" />
</form>
The button calls the javascript function which I use to verify the values of my form before sending to php:
function verifypass() {
var form = document.getElementById("signupform");
var email = document.getElementById("email").value;
var password1 = document.getElementById("passwordone").value;
var password2 = document.getElementById("passwordtwo").value;
var emailcode = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (emailcode.test(email)) {
if (password1.length > 6) {
if (password1 == password2) {
form.submit(); //this statement does not execute
} else {
$("#passwordone").notify("Passwords do not match!", {
position: "right"
})
}
} else {
$("#passwordone").notify("Password is too short!", {
position: "right"
})
}
} else {
$("#email").notify("The email address you have entered is invalid.", {
position: "right"
})
}
}
For some reason, some JavaScript implementations mix up HTML element IDs and code. If you use a different ID for your submit button it will work (id="somethingelse" instead of id="submit"):
<input type="button" value="Sign Up" class="signupinput" onClick="verifypass()" id="somethingelse" />
(I think id="submit" has the effect that the submit method is overwritten on the form node, using the button node. I never figured out why, perhaps to allow shortcuts like form.buttonid.value etc. I just avoid using possible method names as IDs.)
I'm not sure why that's not working, but you get around having to call form.submit(); if you use a <input type="submit"/> instead of <input type="button"/> and then use the onsubmit event instead of onclick. That way, IIRC, all you have to do is return true or false.
I think it would be better if you do it real time, for send error when the user leave each input. For example, there is an input, where you set the email address. When the onfocusout event occured in Javascript you can add an eventlistener which is call a checker function to the email input.
There is a quick example for handling form inputs. (Code below)
It is not protect you against the serious attacks, because in a perfect system you have to check on the both side.
Description for the Javascript example:
There is two input email, and password and there is a hidden button which is shown if everything is correct.
The email check and the password check functions are checking the input field values and if it isn't 3 mark length then show error for user.
The showIt funciton get a boolean if it is true it show the button to submit.
The last function is iterate through the fields object where we store the input fields status, and if there is a false it return false else its true. This is the boolean what the showIt function get.
Hope it is understandable.
<style>
#send {
display: none;
}
</style>
<form>
<input type="text" id="email"/>
<input type="password" id="password"/>
<button id="send" type="submit">Send</button>
</form>
<div id="error"></div>
<script>
var fields = {
email: false,
password: false
};
var email = document.getElementById("email");
email.addEventListener("focusout", emailCheck, false);
var password = document.getElementById("password");
password.addEventListener("focusout", passwordCheck, false);
function emailCheck(){
if(email.value.length < 3) {
document.getElementById("error").innerHTML = "Bad Email";
fields.email = false;
} else {
fields.email = true;
document.getElementById("error").innerHTML = "";
}
show = checkFields();
console.log("asdasd"+show);
showIt(show);
}
function passwordCheck(){
if(password.value.length < 3) {
document.getElementById("error").innerHTML = "Bad Password";
fields.password = false;
} else {
fields.password = true;
document.getElementById("error").innerHTML = "";
}
show = checkFields();
console.log(show);
showIt(show);
}
function showIt(show) {
if (show) {
document.getElementById("send").style.display = "block";
} else {
document.getElementById("send").style.display = "none";
}
}
function checkFields(){
isFalse = Object.keys(fields).map(function(objectKey, index) {
if (fields[objectKey] === false) {
return false;
}
});
console.log(isFalse);
if (isFalse.indexOf(false) >= 0) {
return false;
}
return true;
}
</script>

Categories