Custom validation message on 'type=url' to override standard CSS

雨燕双飞 提交于 2021-02-10 18:02:20

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!