I would like to have a form that:
Display validation messages in a custom format instead of the default style.
Display all invalid field bubbles at once instead of one at a time.
Right now, I am stuck with the boring browser-specific message appearance and I don't see the next error until I correct the last one. This is a really bad user experience, so looking for a few pointers on how to address this.
This is my current JavaScript code:
const contactUsForm = document.querySelector('#Form');
if (contactUsForm) {
function Validate() {
validatedFields = contactUsForm.querySelectorAll('[data-validation-required],[data-validation-format]');
validatedFields.forEach(field => {
/* RegEx patterns */
const emailPattern = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))#((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
if (field.getAttribute('type') === 'email')
{
field.setAttribute('pattern', emailPattern);
}
if (field.validity.valueMissing) {
field.setCustomValidity(field.dataset.validationRequired);
}
else if (field.validity.patternMismatch) {
field.setCustomValidity(field.dataset.validationFormat);
}
else {
field.setCustomValidity('');
}
field.reportValidity();
contactUsForm.checkValidity();
/* Recheck on field value change */
field.addEventListener('change', function() {
field.setCustomValidity('');
Validate();
});
});
}
Validate();
contactUsForm.addEventListener('submit', function(e) {
e.preventDefault;
if (e.checkValidity() == false) {
return false;
}
else {
// form.submit()
}
});
}
Styling validation bubbles/tooltips used to be feature but only exclusive to Chrome, however it got removed.
More information about it here:
How do you style the HTML5 form validation messages?
However, you can create your own tooltips or bubbles to display validation messages. With use of a div container and a span and a little bit of CSS, you can create a bubble with almost any kind of look you can image.
.ttCont {
position: relative;
display: inline-block;
}
.ttCont .ttText {
display: inline-block;
visibility: hidden;
min-width: 200px;
background-color: darkblue;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
opacity: 0;
transition: opacity 0.5s;
/* Place bubble to the right of container */
position: absolute;
z-index: 1;
top: 5px;
left: 105%;
}
.ttCont .ttText::after {
content: " ";
position: absolute;
top: 50%;
right: 100%; /* To the left of the bubble */
margin-top: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent darkblue transparent transparent;
}
.ttCont .ttText.active{
visibility: visible;
opacity: 1;
}
Use of custom bubbles now means that you might need to use less of the ValidityState API, however you can still validate your fields using the same approach. Instead of using field.reportValidity(), you can create a custom function that shows a bubble whenever each field validates
function customReportValidatity(elem, type) {
let msg = "";
///check if validity is based on required or mismatch///
switch (type) {
case 'required':
msg = $(elem).attr('data-validation-required');
///without jQuery
// msg = elem.dataset.validationRequired;
break;
case 'format':
msg = $(elem).attr('data-validation-format');
///without jQuery
// msg = elem.dataset.validationFormat;
break;
default:
break;
}
///make popup appear///
let ttText = $(elem).parent().children('.ttText');
$(ttText).text(msg);
$(ttText).addClass('active');
///without jQuery
// let ttText = elem.parentElement.querySelector('.ttText');
// ttText.innerText = msg;
// ttText.classList.add('active');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
With that styling and custom function, you can apply it to your existing code for any form you are willing to apply to. In this case, I made an example form that takes in a name and email that are required, while the description is not required.
const contactUsForm = document.querySelector('#Form');
const submitBtn = document.querySelector('#submitBtn');
if (contactUsForm) {
function customReportValidatity(elem, type) {
let msg = "";
///check if validity is based on required or mismatch///
switch (type) {
case 'required':
msg = $(elem).attr('data-validation-required');
///without jQuery
// msg = elem.dataset.validationRequired;
break;
case 'format':
msg = $(elem).attr('data-validation-format');
///without jQuery
// msg = elem.dataset.validationFormat;
break;
default:
break;
}
///make popup appear///
let ttText = $(elem).parent().children('.ttText');
$(ttText).text(msg);
$(ttText).addClass('active');
///without jQuery
// let ttText = elem.parentElement.querySelector('.ttText');
// ttText.innerText = msg;
// ttText.classList.add('active');
}
function Validate() {
let isValid = true;
/* RegEx patterns */
const emailPattern = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))#((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
let validatedFields = contactUsForm.querySelectorAll('[data-validation-required],[data-validation-format]');
validatedFields.forEach(field => {
if (field.getAttribute('type') === 'email') {
field.setAttribute('pattern', emailPattern);
}
if (field.validity.valueMissing) {
field.setCustomValidity(field.dataset.validationRequired);
customReportValidatity(field, 'required');
isValid = false;
} else if (field.validity.typeMismatch) {
//using typeMismatch instead of patternMismatch because the regex is not working for emails
field.setCustomValidity(field.dataset.validationFormat);
customReportValidatity(field, 'format');
isValid = false;
}
contactUsForm.checkValidity();
/// Recheck on field value change ///
field.addEventListener('change', function() {
$('.ttText').removeClass('active');
///without jquery
/*document.querySelectorAll('.ttText').forEach((tt)=>{
tt.classList.remove('active');
});*/
Validate();
});
});
return isValid;
}
submitBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
if (Validate()) {
// contactUsForm.submit();
//you can use this output to check if the form will submit
console.log("Form Submitted!");
} else {
return false;
}
});
}
.ttCont {
position: relative;
display: inline-block;
}
.ttCont .ttText {
display: inline-block;
visibility: hidden;
min-width: 200px;
background-color: darkblue;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
opacity: 0;
transition: opacity 0.5s;
position: absolute;
z-index: 1;
top: 5px;
left: 105%;
}
.ttCont .ttText::after {
content: " ";
position: absolute;
top: 50%;
right: 100%;
margin-top: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent darkblue transparent transparent;
}
.ttCont .ttText.active {
visibility: visible;
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<form id="Form">
<div class="ttCont">
<label for="name">Name</label><br/>
<input type="text" name="name" required data-validation-required="Name is required!" /><br/>
<span class="ttText"></span>
</div>
<br/><br/>
<div class="ttCont">
<label for="email">Email</label><br/>
<input type="email" name="email" required data-validation-required="Email is required" data-validation-format="Email must have the format similar to example#email.com!" /><br/>
<span class="ttText"></span>
</div>
<br/><br/>
<div class="ttCont">
<label for="desc">Description</label><br/>
<input type="text" name="desc" data-validation-required="Description is required!" /><br/>
<span class="ttText"></span>
</div>
<br/><br/>
<button type="button" id="submitBtn">Submit</button>
</form>
You can read more about how to create and handle custom tooltips here:
W3Schools Tooltips
LogRocket Tutorial
Related
I am working on a live validation function. The problem is that the aftermath of the conditions in the function executes executes before the last part is met. The entry validation indicator should not turn green until the conditions are met, however this is not the case.
The indicator turns green after the third condition is met. It should not, until all conditions are met. Any suggestions on how I can solve this problem.
My code looks like below.
$(function() {
// Pre-define extensions
var xTension = ".com .net .edu";
$("input").keyup(function() {
// Check the position of "#" symbol
var firstLetter = $(this).val().slice(0, 1);
var lastLetter = $(this).val().slice(-1);
var userXs = "No";
// User provided extension
var userX = $(this).val();
userX = userX.substr(userX.indexOf(".") + 0);
if (xTension.indexOf(userX) > -1) {
if (userX != "") {
userXs = "Yes";
} else {
userXs = "No";
}
} else {
userXs = "No";
};
if ($(this).val().indexOf("#") > -1 && (firstLetter != "#") && (lastLetter != "#") && (userXs != "No")) {
$("#input-status").removeClass("red").addClass("green");
} else {
$("#input-status").removeClass("green").addClass("red");
}
});
});
.rack {
width: 250px;
margin: 0 auto;
}
#input-status {
width: 1px;
height: 3px;
with: 0;
display: inline-block;
transition: all 2s;
}
input {
width: 230px;
height: 30px;
text-align: center;
}
#input-status.green,
#input-status.red {
width: 235px;
background: darkGreen;
transition: all 2s;
}
#input-status.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rack">
<h1>Live Validat.ion</h1>
<input type="text" placeholder="Enter email address">
<div id="input-status">
</div>
</div>
Make xTension an array, not a string. If the user types user#foo.c, userX will be .c and this will be matched by indexOf() with the string, since there's nothing that forces it to match whole words. When you do this, you no longer need to check whether userX is an empty string.
I've made a few other simplifications to the code:
Instead of getting the first and last characters, just test the position of # against appropriate limits.
No need for + 0 after indexOf().
Don't keep calling $(this).val(), put it in a variable.
User a boolean variable for userXs.
$(function() {
// Pre-define extensions
var xTension = [".com", ".net", ".edu"];
$("input").keyup(function() {
var val = $(this).val();
// User provided extension
userX = val.substr(val.indexOf("."));
userXs = xTension.indexOf(userX) > -1;
atPos = val.indexOf("#");
if (atPos > 0 && atPos < val.length - 1 && userXs) {
$("#input-status").removeClass("red").addClass("green");
} else {
$("#input-status").removeClass("green").addClass("red");
}
});
});
.rack {
width: 250px;
margin: 0 auto;
}
#input-status {
width: 1px;
height: 3px;
with: 0;
display: inline-block;
transition: all 2s;
}
input {
width: 230px;
height: 30px;
text-align: center;
}
#input-status.green,
#input-status.red {
width: 235px;
background: darkGreen;
transition: all 2s;
}
#input-status.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rack">
<h1>Live Validat.ion</h1>
<input type="text" placeholder="Enter email address">
<div id="input-status">
</div>
</div>
I'm pretty new with Javascript and jQuery, and can't seem to indentify the reason why my code acts like it does.
I have created two seemingly identical functions to change the background color of an input field.
Their goal is to turn the background color of the given input field to the color #00FF7F if anything is typed in the field. And if not, the field should be transparent.
Code JS:
$(document).ready(function () {
var $input1 = $("#logindata1");
var $input2 = $("#logindata2");
function onChangeInput1() {
$input1.css("background-color", "#00FF7F");
var value = $.trim($(".form-control").val());
if (value.length === 0) {
$input1.css("background-color", "transparent");
}
}
function onChangeInput2() {
$input2.css("background-color", "#00FF7F");
var value = $.trim($(".form-control").val());
if (value.length === 0) {
$input2.css("#background-color", "transparent");
}
}
$input1.on("keyup", onChangeInput1);
$input2.on("keyup", onChangeInput2);
});
css:
#loginbox {
width: 400px;
height: 200px;
margin-left: auto;
margin-right: auto;
margin-top: 25%;
}
.logindata {
margin-left: auto;
margin-right: auto;
margin-top: 20px;
height: 60px;
width: 290px;
transition: 0.25s ease;
}
.form-control {
margin-left: auto;
margin-right: auto;
height: 55px;
width: 288px;
border-style: none;
background-color: transparent;
text-align: center;
border: solid 2px #00FF7F;
transition: 0.25s ease;
font-size: 25px;
font-family: "Trebuchet MS";
}
.form-control:hover {
box-shadow: 0px 0px 30px #2E8B57;
}
::-webkit-input-placeholder {
color: #00FF7F;
}
Simple HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test</title>
<!-- Stylesheet link -->
<link rel="stylesheet" type="text/css" href="assets/style.css">
<!-- jQuery link -->
<script type="text/javascript" src="assets/vendor/jquery-3.1.0.min.js"></script>
</head>
<body>
<div id="loginbox">
<div class="logindata" id="logindata1">
<input type="text" class="form-control" placeholder="Username">
</div>
<div class="logindata" id="logindata2">
<input type="password" class="form-control" placeholder="Password">
</div>
</div>
<!-- Javascript link-->
<script type="text/javascript" src="assets/js/javascript.js"></script>
</body>
On the jsbin above, try typing in both the Username and Password field to see how they react differently.
Images of what happens. Didn't want to include all images here:
http://imgur.com/a/qgubP
I realize there probably is a way to compromise my js/jquery into 1 function that each input field calls instead of have a function for each.
If both of these fields are required, here's a much simpler solution using CSS only.
Add the attribute required to your <input> tags and then use the pseudo-class :valid.
.form-control:valid {
background-color: #00FF7F;
}
Code snippet:
#loginbox {
width: 400px;
height: 200px;
margin-left: auto;
margin-right: auto;
margin-top: 25%;
}
.logindata {
margin-left: auto;
margin-right: auto;
margin-top: 20px;
height: 60px;
width: 290px;
transition: 0.25s ease;
}
.form-control {
margin-left: auto;
margin-right: auto;
height: 55px;
width: 288px;
border-style: none;
background-color: transparent;
text-align: center;
border: solid 2px #00FF7F;
transition: 0.25s ease;
font-size: 25px;
font-family: "Trebuchet MS";
}
.form-control:hover {
box-shadow: 0px 0px 30px #2E8B57;
}
::-webkit-input-placeholder {
color: #00FF7F;
}
.form-control:valid {
background-color: #00FF7F;
}
<div id="loginbox">
<div class="logindata" id="logindata1">
<input type="text" class="form-control" placeholder="Username" required>
</div>
<div class="logindata" id="logindata2">
<input type="password" class="form-control" placeholder="Password" required>
</div>
</div>
jsFiddle : https://jsfiddle.net/7vzjz2u5/3/
jQuery
$(document).ready(function() {
$('.change-background').on('change', function() {
var $this = $(this);
var value = $.trim($this.val());
// toggleClass can be provided a bool value,
// If we provide true we add class, if false we remove class
$this.toggleClass('filled-background', value.length !== 0);
}).change();
// We also want to call a 'change' event on
// all inputs with the change-background class just incase the page has
// pre-filled in values
});
Instead of listening for the keyup event and then running a function, just create a listener on the change event, also if we just apply one class to all inputs we want the background colour to change on, we can just create one listener which will do it for any input with the class change-background.
Html
<div id="loginbox">
<div class="logindata" id="logindata1">
<input type="text" class="change-background form-control" placeholder="Username">
</div>
<div class="logindata" id="logindata2">
<input type="password" class="change-background form-control" placeholder="Password">
</div>
</div>
Css (the extra class for background color)
.filled-background {
background-color: #00FF7F;
}
Also side note
listening for keyup is back, someone may want to copy and paste their username and password and if they do this it won't trigger an keyup event if they use right click and paste.
Your code clears the background color when the length is 0. The way it checks the length is with this snippet of code:
var value = $.trim($(".form-control").val());
The selector $(".form-control") will select all elements with the CSS class of .form-control. This is a problem because there is more than one of them; in this case, it will always return the value from the first element found.
You should change the code to check for the specific control by searching by ID, like so:
var value = $.trim($("#logindata1 input").val()); //get user ID
var value = $.trim($("#logindata2 input").val()); //get password
You have some minor mistakes, but no worry. We can fix it.
First Problem
Other answers are pointing something important: you are trying to get the value selecting all elements with form-control class.
var value = $.trim($(".form-control").val());
You can do it, replacing your selector by your already declared variables $input1 and $input2. This way:
var value = $.trim($input1.val());
var value = $.trim($input2.val());
Second
Ok. First problem solved. The second problem is in your second function. You trying to set an invalid css: $input2.css("#background-color", "transparent");
When should be: $input2.css("background-color", "transparent"); (without #).
Next One
Nice. Next one. The id's you are setting logindata1 and logindata2 are on your divs. So, you are wrongly trying to get the value of the div instead the value of the input. you can fix your selector by appending input, this way:
var $input1 = $("#logindata1 input");
var $input2 = $("#logindata2 input");
Finally
So, finally, it should work:
$(document).ready(function () {
var $input1 = $("#logindata1 input");
var $input2 = $("#logindata2 input");
function onChangeInput1() {
$input1.css("background-color", "#00007F");
var value = $.trim($input1.val());
if (value.length === 0) {
$input1.css("background-color", "transparent");
}
}
function onChangeInput2() {
$input2.css("background-color", "#00007F");
var value = $.trim($input2.val());
if (value.length === 0) {
$input2.css("background-color", "transparent");
}
}
$input1.on("keyup", onChangeInput1);
$input2.on("keyup", onChangeInput2);
});
Your value check is not right. With your jQuery, you are checking the value of both inputs every time.
Try checking the single inputs that you are interested in instead.
$(document).ready(function () {
var $input1 = $("#logindata1");
var $input2 = $("#logindata2");
function onChangeInput1() {
$input1.css("background-color", "#00FF7F");
var value = $.trim($input1.val());
if (value.length === 0) {
$input1.css("background-color", "transparent");
}
}
function onChangeInput2() {
$input2.css("background-color", "#00FF7F");
var value = $.trim($input2.val());
if (value.length === 0) {
$input2.css("#background-color", "transparent");
}
}
$input1.on("keyup", onChangeInput1);
$input2.on("keyup", onChangeInput2);
});
I've made a simple jQuery script which stores values "voted1", "voted2", "voted3" in localStorage. The problem is that on click it stores all values at the same time, and I need it per click as it should be later called (e.g. if "value3" exists begin jQuery logic...)
I can't figure this out, after weeks of testing..
HTML:
[gallery link="none" size="medium" ids="102,13,27,25,23,15" orderby="rand"]
<div class="exists" style="display: none;">Thank you for voting!</div>
CSS:
.gallery-item a {
background-color: black;
border: 1px solid orange;
border-radius: 6px;
color: orange;
display: inline-table;
font-size: 14px;
font-weight: bold;
max-width: 100%;
width: 32%;
}
.exists {
background-color: black;
border-radius: 18px;
box-shadow: 1px 3px 20px -3px grey inset;
display: block;
height: 32%;
left: 24%;
margin-left: 10%;
margin-right: 10%;
margin-top: 10%;
max-width: 100%;
padding-left: 12%;
padding-top: 6%;
position: fixed;
top: 23%;
width: 36%;
z-index: 999999;
color: olivedrab;
font-weight: bold;
cursor: context-menu;
}
.voted {
background-color: green !important;
}
jQuery:
$(document).ready(function() {
var voteLink = $('.gallery-item a');
var votedYes = $('.exists');
voteLink.one('click', function() {
// localStorage.setItem('voted1', 'yes1');
$(this).text('Thank you!');
$(this).addClass('voted');
})
voteLink.one('click', function() {
// localStorage.setItem('voted2', 'yes2');
$(this).text('Thank you!');
$(this).addClass('voted');
})
voteLink.one('click', function() {
localStorage.setItem('voted3', 'yes3');
$(this).text('Thank you!');
$(this).addClass('voted');
if($('.voted').length === 3){
voteLink.fadeOut('slow');
$('.exists').fadeIn(1800);
}
if (localStorage.getItem("voted3")) {
voteLink.remove();
votedYes.fadeIn(1800);
}
});
As I said, on first click it places all values in localStorage and I need this separated.
Thanks guys.
$(document).ready(function() {
var voteLink = $(".gallery-item a");
var votedYes = $(".exists");
if (localStorage.getItem("count") === null) {
localStorage.setItem("count", 1)
}
if (!(localStorage.getItem("voted3") === "yes3")) {
var i = Number(localStorage.getItem("count")),
fn = function(e) {
if (i < 3) {
localStorage.setItem("voted" + i, "yes" + i);
$(this).text("Thank you! for vote " + i)
.addClass("voted" + i);
localStorage.setItem("count", 1 + i);
i = Number(localStorage.getItem("count"));
} else {
localStorage.setItem("voted" + i, "yes" + i);
$(this).text("Thank you! for vote " + i)
.addClass("voted" + i)
.fadeOut("slow");
if (localStorage.getItem("voted3") === "yes3") {
voteLink.remove();
votedYes.fadeIn(1800);
}
}
};
voteLink.on("click", fn);
} else {
// if `localStorage` has property `"voted3"` and value equals `"yes3"`,
// do stuff
}
})
Caveat: This answer may be completely off, since your question comes without all the details of your use case. However ...
The following code assumes that ...
up to 3 votes shall be recorded in localStorage
in order to cast the vote n+1, vote n must have been recorded before.
Either register the handlers contingent on the content in localStorage:
if (
localStorage.getItem("voted1")
&& !localStorage.getItem("voted2")
) {
voteLink.one('click', function() {
localStorage.setItem('voted2', 'yes2');
//...
});
}
... or test the localStorage contents inside your event handler:
fn_vote2 = function() {
if (
localStorage.getItem("voted1")
&& !localStorage.getItem("voted2")
) {
localStorage.setItem('voted2', 'yes2');
//...
voteLink.off('click', fn_vote2);
}
};
voteLink.on('click', fn_vote2);
The generalization for vote1, vote3 should come easy. Note that the latter solution implies that you register the handler not just for a single event. Instead you deregister it upon success.
The advantage of the method is the option for cascaded voting without reloading the page.
Btw, since localStorage persists over sessions, it is advisable not to use generic keys like vote<n>.
Am creating an HTML page with some buttons to create the input boxes. The buttons should behave like toggle one. ie, on first click input box should appear and if the same button in clicked again that particular input box need to disappear. Button toggle i have managed. But div is not creating
This is my toggle button
<button class="btn" id="button_rd" onclick="setColor('button_rd', '#101010')";>one</button>
Following is the javascript
var count = 1;
function setColor(btn, color) {
var property = document.getElementById(btn);
if (count == 0) {
property.style.backgroundColor = "#f4543c"//red
property.style.borderColor = "#f4543c"
count = 1;
}
else {
property.style.backgroundColor = "#00a65a"//green
property.style.borderColor = "#008d4c"
count = 0;
var newdiv = '<div class="form-group"><label for="exampleInputEmail1">email</label>'
+'<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email"></div>'
document.getElementById("create").append(newdiv);
}
}
And below is the place where I need the input box to display(inside this div)
<div class="box-body" id="create">
</div>
If you're happy to use Jquery, Something like this may be what you're looking for.
it's not so much as 'creating' an element, more actually 'toggling' its visibility
$(document).ready(function() {
$('[id^=bool]').click(function() {
var id = $(this).attr("id").substr($(this).attr("id").length - 1);
$('[id^=bool' + id + '] .switcher').toggleClass("switched");
var x = $('[id=input' + id + ']').length;
if (x > 0) //there is one there
{
$('[id=input' + id + ']').remove();
} else {
$('body').append('<input type="text" id="input' + id + '" placeholder="input ' + id + '" />');
}
});
});
.bool {
height: 40px;
width: 100px;
background: darkgray;
position: relative;
border-radius: 5px;
overflow: hidden;
box-shadow: inset 5px 0 6px gray;
border: 1px solid black;
}
.bool:before {
content: "On";
left: 10%;
position: absolute;
top: 25%;
}
.bool:after {
content: "Off";
right: 10%;
position: absolute;
top: 25%;
}
.switcher {
height: 100%;
width: 50%;
position: absolute;
background: lightgray;
top: 0;
left: 0;
z-index: 5;
transform: translateX(0px);
transition: all 0.5s;
border-radius: 5px;
box-shadow: inset 0 0 6px black;
}
.switched {
transform: translateX(50px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bool" id="bool1">
<div class="switcher"></div>
</div>
<div class="bool" id="bool2">
<div class="switcher"></div>
</div>
Edit History
Altered snippet to include 2 toggles, as per comments
refactored jquery method with help from Tambo
altered markup to 'append' and 'remove' instead
OnClick write following code to hide:
document.getElementById('create').style.display = 'none';
And following code to show:
document.getElementById('create').style.display = 'block';
Like:
JavaScript:
<script type="text/javascript">
var count = 1;
function hidShow()
{
if(count == 1)
{
document.getElementById('create').style.display = 'none';
count = 0;
}
else
{
document.getElementById('create').style.display = 'block';
count = 1;
}
}
</script>
HTML:
<button id="button_rd" onClick="hidShow()">one</button>
<div class="box-body" id="create">
<input type="text" id="txt"/>
</div>
instead of
document.getElementById("create").append(newdiv);
'innerHTML' works for me, like below:
document.getElementById("create").innerHTML = '<div class="form-group"><label for="exampleInputEmail1">email</label>'
+'<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email"></div>'
to remove the div on toggle i used
$('div_id').remove();
I have styled filed upload button and added preview image before upload... basically everything works as a charm in all browsers except IE...
Now to bring you my idea closer it looks like:
http://postimage.org/gallery/22cvzh2g/bcd61d61/
Is there a reason why image isn't showing in IE? I tried in IE9, but I just get the path, while the $('#background-preview').removeClass('hidden'); seems not to be working as it's not removing class hidden...
...also in IE and Opera as file path you will note C:/fakepath/etc... while in FireFox, Chrome and normal browsers it displays just file name. Any help is highly appreciated!
Now in header I have:
<script>
function clearFileInput() {
var oldInput = document.getElementById("upload-bg");
var newInput = document.createElement("input");
newInput.type = "file";
newInput.id = oldInput.id;
newInput.name = oldInput.name;
newInput.onchange = oldInput.onchange;
newInput.className = oldInput.className;
newInput.style.cssText = oldInput.style.cssText;
// copy any other relevant attributes
oldInput.parentNode.replaceChild(newInput, oldInput);
$('#background-preview').addClass('hidden');
var oldInput1 = document.getElementById("FileField");
var newInput2 = document.createElement("input");
newInput2.type = "text";
newInput2.id = oldInput1.id;
newInput2.className = oldInput1.className;
newInput2.style.cssText = oldInput1.style.cssText;
oldInput1.parentNode.replaceChild(newInput2, oldInput1);
}
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#background-image')
.attr('src', e.target.result)
.width(250)
.height(170);
$('#background-preview').removeClass('hidden');
};
reader.readAsDataURL(input.files[0]);
}
}
In body section where actual button is:
<div id="FileUpload">
<input id="upload-bg" type='file' onchange="readURL(this);getElementById('FileField').value = getElementById('upload-bg').value;" />
<div id="BrowserVisible"><input type="text" id="FileField" /></div>
</div>
<div id="background-preview" class="hidden"><img id="background-image" src="#" alt="Bad Image File !" /> </div>
And the CSS that takes care for the customizing file input is:
#FileUpload {
position:relative;
height: 50px;
}
#BrowserVisible {
margin: 5px 0px 5px 0px;
position: absolute;
top: 0px;
left: 0px;
z-index: 1;
background:url(images/button-browse.png) 100% 0px no-repeat;
height:42px;
width:290px;
}
#FileField {
border: 1px solid #BDBDBD;
font-size: 13px;
height: 40px;
margin: 0;
padding: 0;
width: 215px;
}
#upload-bg {
position:relative;
width:290px;
height:43px;
text-align: right;
-moz-opacity:0;
filter:alpha(opacity: 0);
opacity: 0;
z-index: 2;
}
#clear-bg-upload {
position: absolute;
top: 0px;
right: 0px;
width: 16px;
height: 16px;
background: url(images/icon-delete-input.png) top center no-repeat;
}
#background-preview {
border: solid 1px #ccc;
padding: 5px;
position: relative;
display: inline-block;
border-radius: 5px;
-o-border-radius: 5px;
-icab-border-radius: 5px;
-khtml-border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
}
#background-preview.hidden {
display: none;
}
#background-preview img {
margin: 0px auto;
display: block;
max-height: 140px;
max-width: 180px;
width: auto;
}
----------------------------- EDITED -------------------------------
Ok, I went to different approach via Ajax (using) upload and all is wonderful... I just can't figure how to send field value only. Right now it's sent like form, but is there a way to trigger send only the field. Right now it's warped in #FileUploadForm, but I want to use this within a form and since forms can't be nested... I am kind of stuck... except having two forms like I have now, but I would like that file upload filed to be sent like it is now, just without having to wrap it in it's own form.
This is script I am using:
function showRequest(formData, jqForm, options) {
var fileToUploadValue = $('#fileToUpload').fieldValue();
if (!fileToUploadValue[0]) {
$('#result').html('Please select a file.');
return false;
}
$("#loading").show();
return true;
}
function showResponse(data, statusText) {
$("#loading").hide();
if (statusText == 'success') {
var msg = data.error.replace("##", "<br />");
if (data.img != '') {
$('#result').removeClass('hiddenmessage');
$('#result').html('<img src="uploads/thumbs/' + data.img + '" /> ');
// $('#message').html('Click here');
// $('#FileUploadForm').html('');
} else {
$('#result').removeClass('hiddenmessage');
$('#result').html(msg);
}
} else {
$('#result').removeClass('hiddenmessage');
$('#result').html('Unknown error!');
}
}
function StartFileUpload() {
$('#message').html('');
$('#FileUploadForm').ajaxSubmit({
beforeSubmit: showRequest,
success: showResponse,
url: 'upload.php',
dataType: 'json'
});
return false;
}
$('#fileToUpload').live('change', function () {
StartFileUpload();
});
Let's start with paths — in HTML/JS, you can't get full path to attached file due to security concerns. All you can get is file name.
Usually the best approach is to upload file to server with JavaScript when user selects file and then grab preview from that server. You could provide some "delete" button which would enable users to remove pics they uploaded by mistake.
This would enforce deep changes in your application. I recommend File Uploader plugin. Writing your own solution from scratch will be very painful because it requires many hacks for different browsers.