I have a form that uses very basic input validation using javascript onSubmit before the server side processing begins in PHP.
However, due to the time the PHP script takes to process (uploading images etc) I am trying to use the same onSubmit function to display a "please wait" notice if it passes validation. Or is there a better way? I tried in PHP, but the processing has to complete before I can echo any output. Anything I have tried from other SO posts stops the validation process.
<form id="form" method="post" action="" onsubmit="return Validate(this)" autocomplete="off">
Current Javascript Example
function Validate(myForm) {
var error = '';
// Example Filed
if(myForm.name.value == '') {
error += '- Please enter your Name.\n';
}
// Show Error Notice
if(error != '') {
error = 'The form has not been completed correctly, please check the following:\n\n' + error;
alert(error); // Displays Error
return false;
} else {
// Allows the form to move on to PHP Processing
// Need to Show Waiting Notice here
return true;
}
}
CSS & HTML Waiting Notice (Initially Hidden)
<style>
#processing {
display:block;
position: fixed;
top: 0;
left: 0;
background: rgba(255,255,255,0.8);
width: 100%;
height: 100%;
}
#popup {
width: 300px;
min-height: 160px;
padding:20px;
background-color: #fff;
border: 5px solid #06C;
text-align: center;
color: #202020;
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -100px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
}
#popup img {
height:60px;
width:60px;
}
</style>
<div id="processing">
<div id="popup">
<img width="60" height="60" src="../waiting.gif" />
<h3>Please Wait!</h3>
<p>The form is processing...</p>
</div>
</div>
Any help would be appreciated
All you need to do is have the "...Please Wait..." element already present in the document, but hidden and then show it when the submit takes place. You do this by applying a CSS class to the element in the HTML, which hides it initially and then remove that class when the form is valid.
A couple of side notes...
Don't use inline HTML event attributes (onsubmit, onclick, etc.). That is how events were registered 20 years ago and there are many drawbacks to using them. Unfortunately, because most people just copy what others have done, the use of this approach just will not die. Instead, follow modern standards and use .addEventListener().
Also, don't ever name an element or a variable name as name is a property of the Global window object and the use of that name can cause problems in the code.
// Get references to the DOM elements that your code will need
var frm = document.getElementById("form");
var wait = document.getElementById("processing");
var userName = document.getElementById("txtName");
frm.addEventListener("submit", validate); // Set up events the modern, standards-based way
// All event handlers will automatically be passed a reference
// to the event object for that event
function validate(evt) {
var error = '';
// Example Filed
if(userName.value == '') {
error += '- Please enter your Name.\n';
}
// Show Error Notice
if(error != '') {
error = 'The form has not been completed correctly, please check the following:\n\n' + error;
alert(error); // Displays Error
evt.preventDefault(); // Stop the event
} else {
// Allows the form to move on to PHP Processing
// Need to Show Waiting Notice here
wait.classList.remove("hidden"); // Remove the hidden class
}
}
#processing {
display:block;
position: fixed;
top: 0;
left: 0;
background: rgba(255,255,255,0.8);
width: 100%;
height: 100%;
}
#processing.hidden { display:none } /* This hides the message by default */
#popup {
width: 300px;
min-height: 160px;
padding:20px;
background-color: #fff;
border: 5px solid #06C;
text-align: center;
color: #202020;
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -100px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
}
#popup img {
height:60px;
width:60px;
}
<form id="form" method="post" action="#" autocomplete="off">
<input type="text" id="txtName">
<input type="submit">
</form>
<div id="processing" class="hidden">
<div id="popup">
<img width="60" height="60" src="../waiting.gif" />
<h3>Please Wait!</h3>
<p>The form is processing...</p>
</div>
</div>
On your javascript validation, you could let the user know the image is loading by showing a simple message.
<div class="loading" style="display:none;">Loadin ...</div>
function Validate(myForm) {
var error = '';
// Example Filed
if(myForm.name.value == '') {
error += '- Please enter your Name.\n';
}
// Show Error Notice
if(error != '') {
error = 'The form has not been completed correctly, please check the following:\n\n' + error;
alert(error); // Displays Error
return false;
} else {
// Allows the form to move on to PHP Processing
// Need to Show Waiting Notice here
// show the user the image is loading
$('#form .loading').show();
return true;
}
}
After it loads you may remove the message once you get a response from the server.
$('#form .loading').hide();
Related
I am building my first web app using Flask. I'm new to html/ JavaScript/ CSS - please bear with me.
The app does the following: The user uploads an Excel file as follows:
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file" id="file" />
Then they select certain parameters using dropdown lists. When the user clicks "Submit", the data is manipulated using pandas and a new file is exported in Excel.
I managed to add a spinner to the "submit" button using html and CSS. I added an event listener to my JavaScript so the spinner is activated when the button is clicked. At the moment, the spinner runs indefinitely, however I would like the spinner to stop and the button text to revert to "submit" once the operation is finished, i.e. the export is complete. Does anybody know how I can accomplish this?
Here is my html:
<button type="submit" id="submit" class="button">
<span class="button__text">Submit</span>
</button>
Here is my CSS:
<style>
.button {
position: relative;
padding: 8px 16px;
background: #009579;
border: none;
outline: none;
border-radius: 2px;
cursor: pointer;
}
.button:active {
background: #007a63;
}
.button__text {
font: bold 20px "Quicksand", san-serif;
color: #ffffff;
transition: all 0.2s;
}
.button--loading .button__text {
visibility: hidden;
opacity: 0;
}
.button--loading::after {
content: "";
position: absolute;
width: 16px;
height: 16px;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
border: 4px solid transparent;
border-top-color: #ffffff;
border-radius: 50%;
animation: button-loading-spinner 1s ease infinite;
}
/*animate spinner - spin from 0 to 1 turn*/
#keyframes button-loading-spinner {
from {
transform: rotate(0turn);
}
to {
transform: rotate(1turn);
}
</style>
Here is my JavaScript:
<script type="text/javascript">
(() => {
const elem = document.getElementById('submit');
elem.disabled = false;
elem.addEventListener('click', e=> {
elem.classList.add('button--loading');
});
})();
</script>
Basically, your frontend (the HTML/Javascript) needs some way of knowing when "the export is complete". Depending on your definition of "export" and "complete".
At the most rudimentary level, you could have the frontend poll the server every second after the upload starts, and have the server return some kind of status as to what the state of the process is. This could be as simple as:
GET /status/1234
> {"status": "IN_PROGRESS"}
which, when the "export is complete" switches to:
> {"status": "COMPLETE"}
And when the frontend receives the COMPLETE status, it removes the spinner. Notice the 1234. You will need some way of identifying the upload in progress. One way to do this would be to assign it a random id when you first accept the form, so the initial POST /upload returns > {'id': 1234} which the client can then use for the subsequent polling.
If "export is complete" actually only means that the file is finished uploading, you could still use a polling method, but a much slicker way is to use the client (web browser) method of determining how many bytes have been sent (see this SO answer).
I would like the admin user of my app to be able to invite new users.
The flow is:
admin user input new user name and email
generate a random password for the new user
display name, email and password for review
admin user click a button, and ajax sends name, email and password to server
server create new user
The rest is easy, except for step 3.
What I want is something like: <p>{password}</p>, and it will be displayed as ****** for default.
If admin user want to see the password, click some button and the password will show as normal text.
I know how to do this with <input>, but is it possible without using <input>?
My current solution is managing a show state for the <p> with javascript, if show === false, display <p>********</p>, else display <p>{password}</p>.
But I'd be happy to see a simpler solution without javascript.
UPDATE
A slightly different solution based on this; password keeps showing even when mouse moved away.
Any element with a tabindex
could be focused
p {
position: relative;
width: 100px;
}
p:after{
content: '*****';
position: absolute;
background-color: white;
right: 0;
left: 0;
top:0;
}
p:focus:after{
content: ''
}
<p tabindex="-1">password1</p>
<p tabindex="-1">password2</p>
try this
[data-pass]:hover:after {
content: attr(data-pass);
}
<p data-pass="{password}">********</p>
now could be selected
p {
position: relative;
width: 100px;
}
p:after{
content: '*****';
position: absolute;
background-color: white;
right: 0;
left: 0;
top:0;
}
p:hover:after{
content: ''
}
<p>{password}</p>
Thanks #ahmad, I came up with this. Would be better if the text could be selected... (pseudo element can't be selected)
[data-pass]:before {
content: "****";
}
[data-pass]:hover:before {
content: "";
}
[data-pass]:hover:after {
content: attr(data-pass);
}
<p data-pass="{password}"></p>
Alternative
input[type=checkbox] {
display: none;
}
input[type=checkbox]:checked~.remove-check {
display: none;
}
input[type=checkbox]:checked~#password {
display: block;
}
#password {
display: none;
position:absolute;
top:0; left:0; background-color:yellow;
padding:0; margin:0;
}
<label class="remove-check" for="chk">*****</label><input id="chk" type="checkbox">
<p id="password">{password}</p>
I am using AJAX to get some data and fill-up the form. Data is quite large so it takes some time to get from DB and fill up in fields, so while all doing this stuff i am showing loading icon.
Now there is a submit button in a form, and we want - that form should not be submitted until that loading icon gone away. I have done this thing so far.
I am using prevent default - if user hit the submit button before AJAX done its work and that loading icon gone away, and after AJAX done its work that form got submitted.
But now issue is, if i hit submit - because of prevent default is doesn't shows loading icon in browser tab (so user might think form submit button isn't working and hit it multiple times,(we got this data from GOOGLE ANALYTICS))
but form will automatically submits, when AJAX completes it works.
Is it possible to show that "Browser Tab Loading Icon" ?
I know other things like (hide submit button and etc etc)
Here is my piece of code :
$("#formsech").submit(function(event){
submit = -1;
if ( $("#loading").css('display') == 'none' ){
submit = 1;
}
else{
event.preventDefault();
}
});
setInterval(function(){
if(submit == -1){
if($("#loading").css('display') == 'none' ){
submit = 1;
}
}
}, 100);
setInterval(function(){
if(submit == 1){
$("#formsech").submit();
submit = 0;
}
}, 100);
Any help would be highly appreciated.
If you are using AJAX, you can do simply like this:
$(form).submit(function (e) {
e.preventDefault();
$(form).css("cursor", "loading");
$("#loading").show();
$.post("/path/to/url", $(form).serialize(), function () {
$("#loading").hide();
$(form).css("cursor", "initial");
alert("Saved");
});
});
A better example using a setTimeout just for demo purpose.
$(function() {
$(".loading").removeClass("hidden").hide();
$("#myform").submit(function() {
$(".loading").fadeIn();
setTimeout(function() {
$(".loading").fadeOut();
}, 2000);
});
});
* {
font-family: 'Segoe UI', sans-serif;
}
.loading {
background: url("http://www.arabianbusiness.com/skins/ab.main/gfx/loading_spinner.gif") center center no-repeat;
width: 150px;
height: 150px;
position: absolute;
z-index: 1;
opacity: 0.5;
}
.hidden {
display: none;
}
#myform {
display: block;
position: relative;
width: 150px;
line-height: 150px;
text-align: center;
border: 1px solid #ccc;
overflow: hidden;
}
<script src="https://code.jquery.com/jquery-1.9.1.js"></script>
<form action="." id="myform">
<div class="loading hidden"></div>
<input type="submit" />
</form>
The setTimeout is just for mimicking the AJAX delay. The z-index will not allow the user the press the submit button.
You can use below html in your page.
<div id="overlay"></div>
The css will be
#overlay {
background-color: rgba(0, 0, 0, 0.8);
z-index: 99;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: none;
}
Before ajax call use following code
$("#overlay").show(500);
After ajax call is completed write this:
$("#overlay").hide();
I have a progress bar that should react to input if the input is blank or equals 0 the inner progress div should have no background. For all other inputs it should be fill. It does work for the condition that the input is blank however after the input is entered there is no change reflected.
var first = document.getElementById("first");
if (a.innerHTML == '') {
first.style.background = "none";
} else {
first.style.background = "#e91b23";
}
.progress_bars_vertical_holder {
display: inline-block;
width: 100%;
position: relative;
}
.progress_bars_vertical {
display: inline-block;
position: relative;
float: left;
margin: 0px 2% 0px 0px;
}
.progress_bars_vertical:last-child {
margin: 0px;
}
.progress_bars_vertical .progress_content_outer {
height: 200px;
position: relative;
}
<input id="a" onkeypress="return tisNumberKey(event)" type="text" style="height: 250px; margin-top: 10px; width: 75%; text-align: center; font-size: 100px;" type="text" data-in="" />
<div class="progress_bars_vertical_holder vertical">
<div class="progress_bars_vertical background_color" style="width: 99.7%;">
<div class="progress_content_outer">
<div data-percentage="30" id="first" class="progress_content" style="height: 50%; background-color: rgb(22, 146, 159);"></div>
</div>
</div>
</div>
http://codepen.io/georgiemathews/pen/mJGBOV
It should be:
first.style.background = "#e91b23";
^---
The # marks that string as a hex value. Otherwise it's just seen as some random garbage.
You had a few typos. I grabbed a copy of your CodePen demo and here is a working version you can play with.
HTML
I got it working and the red progress bar is added when you type into the box. But, when you clear the input range, the indicator stayed red because it was simply looking for a keypress. I changed it to oninput to get the desired behavior.
You also had a typo in your function - it said tisNumberKey - changed to isNumberKey.
<input id="a" oninput="return isNumberKey(event)" type="text" style="height: 250px; margin-top: 10px; width: 75%; text-align: center; font-size: 100px;" type="text" data-in="" />
JavaScript
You weren't calling the function with anything. The HTML was trying to call the script, but there was no named function. Adding function isNumberKey(event) to the script allows it to run when you type in the input range.
Finally, I changed the logic for adding the class. If the field is not empty, make it red. Ran more consistently with the other changes. Working script is below:
function isNumberKey(){
var first = document.getElementById("first");
var a = document.getElementById("a");
if (a.value !== '') {
first.setAttribute("class", "red-bg");
} else {
first.setAttribute("class", "no-bg");
}
}
I'm working with a simple html type="file" input, and I'm having an issue in Chrome. Specifically, when you browse to and choose a file, it saves the value. However, if you re-browse, then press cancel it will clear out the value.
The html is simple:
<input type="file">
Here is a simple fiddle- http://jsfiddle.net/78ghn/.
This doesn't happen in other browsers -- is there a way to force Chrome to retain the value??
function f()
{
document.getElementById("b").appendChild(document.getElementById("a"));
document.getElementById("d").innerHTML = document.getElementById("c").innerHTML
document.getElementById("alert").innerHTML = 'Your last file was '.concat(document.getElementById("b").lastChild.value.slice(12))
}
function g()
{
if(document.getElementById("b").lastChild.value)
{
document.write("You have submitted ".concat(document.getElementById("b").lastChild.value.slice(12)));
}
else
{
document.write("You have submitted nothing.");
}
}
#a
{
opacity: 0;
width: 100%;
height: 100%;
}
#c
{
display: none;
}
#d
{
width: 100%;
height: 100%;
}
#e
{
background-color: green;
border: 2px solid black;
color: white;
font-size: 16pt;
width: 180px;
height: 90px;
}
#f
{
position: relative;
left: 25%;
bottom: 70%;
}
<form>
<div id='e'>
<span id='d'>
<input type="file" onchange='f();' id='a'>
</span>
<span id='f'>Select File</span>
</div>
<input type='button' value='Submit' onclick='g();'>
</form>
<span id='alert'>You have chosen no files.</span>
<ul id='b'>
</ul>
<form id='c'>
<input type="file" onchange='f();' id='a'>
</form>
I was unable to find a native implementation for this, so I tried my own workaround. It takes input from a custom CSS button overlay, then adds the actual input element to a list and replaces it with an empty one. The value is read and displayed, as it would be with a normal input. It is not included, but submitting it would involve moving the original input (last element of ul with id='b') to a form and submitting it via JavaScript. It is not optimal, but it does work.