问题
If a user does not search a url on the front end, I would like the design to appear as follows
Currently, this my form, which is using the type="url" to provide the validation without having to make a regex.
Here is a copy of my current form with a post request
<form action="POST" id="Submit">
<div class="inner-form">
<div class="input-field first-wrap">
<div class="svg-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z "></path>
</svg>
</div>
<input id="search" type="url" name="url" placeholder="Paste a domain here" />
</div>
<div class="input-field second-wrap">
<button id="button" class="btn-search" onclick="searchIt()" value="press" type="submit">SEARCH </button>
</div>
</div>
</form>
and here is my script tag after the form
let progress = 0;
const maxTime = 5000; // 5 seconds
let interval = null;
function searchIt() {
let form = document.querySelector('form')
console.log(form)
form.addEventListener('submit', async(e) => {
// onclick or the event that start the call
interval = setInterval(() => {
progress = progress >= 100 ? 100 : progress + 1
document.getElementById('myprogress').style.width = `${progress}%`
// end interval and wait at 100%
if(progress == 100) clearInterval(interval);
}, maxTime/100)
document.getElementById('loadingcontainer').style.display = ""
e.preventDefault()
let urlIN = form.url.value
let url = encodeURIComponent(urlIN)
console.log(url)
try {
const data = await fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: url
})
}).then(res => {
document.open()
res.text().then(function(text) {
document.write(text)
// Hide the progressbar, stop the timer and reset progress
clearInterval(interval);
progress = 0;
document.getElementById('myprogress').style.width = "0%"
document.getElementById('loadingcontainer').style.display = "none";
});
})
} catch (err) {
console.error(err)
}
})
}
How could I achieve the specified design in the mockup? I cannot seem to get this one for the life of me
回答1:
The only part of your code that runs initially, on page load, are your three statements declaring your variables:
let progress = 0;
const maxTime = 5000; // 5 seconds
let interval = null;
and the declaration of your function searchIt() — note that the function is not being run, it is only being declared, so the code within that function such as form.addEventListener('submit', ...) has not executed yet.
Meanwhile, you have a submit button with an inline event handler declared
<button id="button" class="btn-search" onclick="searchIt()"
value="press" type="submit">SEARCH</button>
so when "SEARCH" is clicked, then searchIt is run and the submit event-handler is attached, but by then it's too late — you're already in the process of submitting the form, so your attempt to override the browser's handling of validation isn't even attached yet.
In the "script tag after the form" you need to do let form = document.querySelector('form') and form.addEventListener('submit',...)
outside of the searchIt() function, before it is run, such as right after the line let interval = null;
In addition, the use of async directly on the event listener for the submit handler — form.addEventListener('submit', async(e) => ...) — makes the whole handler asynchronous, so the call in there to e.preventDefault() will likely not occur to prevent the default submit handling. The only part of the code you really want to be async is the fetch() and its handling of the fetch results. For that reason I would separate it into its own function so the submit handler becomes, in pseudo-code:
form.addEventListener('submit', function(e) {
e.preventDefault();
doValidation();
if (it is valid) call the async function;
}
You mention in a comment that "The default type=url css is still showing up." — you need to tell the browser not to do its validation, by using the novalidate attribute on the form
<form action="POST" id="Submit" novalidate>
Finally, I would change the names used for some of the IDs to be more descriptive of the purpose of a thing; the button's ID is "button", which describes what the thing is, a button, but doesn't describe its purpose. What does that button do? It initiates the search, so maybe <button id="search"> — while the field is where you enter the target URL you want to search, so <input id="targeturl"...>
I've changed several names in the example below.
Here's the page with the changes discussed. Note that with the "real" work encapsulated in a function you might want to move the maxTime, progress, and interval variables into that function.
<!DOCTYPE html>
<html>
<head>
<title>Kyle's URL field</title>
<style>
#errors {
display: none;
}
#errors.has-error {
display: block;
}
#errors #message {
color: #e45b3f;
}
</style>
</head>
<body>
<main>
<form action="POST" id="searchform" novalidate>
<div class="inner-form">
<div class="input-field first-wrap">
<div class="svg-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z "></path>
</svg>
</div><!-- svg-wrapper -->
<input id="targeturl" type="url" name="url"
placeholder="Paste a domain here"
required pattern="^https?://www\..*$"
>
</div><!-- input-field first-wrap -->
<div class="input-field second-wrap">
<button id="search" class="btn-search" value="press" type="submit">SEARCH</button>
</div>
<div id="errors">
<span id="message"></span>
</div>
</div><!-- inner-form -->
</form>
</main>
</body>
<script>
const maxTime = 5000; // 5 seconds
let progress = 0;
let interval = null;
const form = document.querySelector('form');
const urlField = document.getElementById('targeturl');
const errors = document.getElementById('errors');
const message = document.getElementById('message');
form.addEventListener('submit', function(e) {
e.preventDefault();
console.log('handling the form submit here');
const valid = urlField.checkValidity();
console.log(`valid = ${valid}`);
if (valid) {
clearError();
console.log('about to run the async portion');
doTheAsyncStuff(e);
}
else {
console.log('twiddle with the DOM to display your custom error message');
showError("Yikes! That's not a valid URL");
}
});
function showError(msg) {
message.innerText = msg;
errors.classList.add('has-error');
}
function clearError() {
message.innerText = '';
errors.classList.remove('has-error');
}
async function doTheAsyncStuff(e) {
console.log('now running the async function "doTheAsync"');
}
</script>
</html>
来源:https://stackoverflow.com/questions/65946954/custom-validation-message-on-type-url-to-override-standard-css