2
\$\begingroup\$

Created a validation form in vanilla JS. Due to my little experience, I have a bunch of "if" here, I can not transfer the coordinates of Yandex.Maps to another function for validation, and it is still unknown what. With the coordinates, I "crutch" by saving them to an invisible div :-) I deleted my Api key, so I won't be able to get the coordinates in the example, I don't know if it's worth giving the key to public access :-) The code is working.

Tell me how I can reduce the code or how to perform form validation without my crutch using a div :-) (pass the variable to another function so that when the button is clicked, it checks that the coordinates are entered)

let errorName = document.querySelector(".name-error");
let errorNumber = document.querySelector(".number-error");
let errorEmail = document.querySelector(".email-error");
let errorMap = document.querySelector(".map-error");
let completed = document.querySelector(".mailForm__completed");

function viodChecker() {
    let name = document.querySelector(".mailForm__name").value;
    let number = document.querySelector(".mailForm__number").value;
    let Email = document.querySelector(".mailForm__email").value;
    let Coords = document.querySelector(".coords");
        if (name === "") {
            errorName.style.display = "block";
        }
        if (name !== "") {
            errorName.style.display = "none";
        }
        if (number === "") {
            errorNumber.style.display = "block";
        }
        if (number !== "") {
            errorNumber.style.display = "none";
        }
        if (Email.indexOf("@") === -1) {
            errorEmail.style.display = "block";
        }
        if (Email.indexOf("@") !== -1) {
            errorEmail.style.display = "none";
        }
        if (Email.indexOf("@") !== -1) {
            errorEmail.style.display = "none";
        }
        if (Coords.textContent === "") {
            errorMap.style.display = "block";
        }
        if (Coords.textContent !== "") {
            errorMap.style.display = "none";
        }
        if (name !== "" && number !== "" && Email.indexOf("@") !== -1 && Coords.textContent !== "")  {
            completed.style.display = "block";
        }
}


ymaps.ready(init);

function init() {
    var myPlacemark,
        myMap = new ymaps.Map('map', {
            center: [40.391917, -73.524590],
            zoom: 17,
            controls: ['geolocationControl', 'searchControl']
        });

    // We listen to the click on the map.
    myMap.events.add('click', function (e) {
        var coords = e.get('coords');

        // If the label has already been created, just move it.
        if (myPlacemark) {
            myPlacemark.geometry.setCoordinates(coords);
        }
        // If not, we create.
        else {
            myPlacemark = createPlacemark(coords);
            myMap.geoObjects.add(myPlacemark);
            // Listen to the drag-and-drop event on the label.
            myPlacemark.events.add('dragend', function () {
                getAddress(myPlacemark.geometry.getCoordinates());
            });
        }
        getAddress(coords);
    });

    // Create a label.
    function createPlacemark(coords) {
        return new ymaps.Placemark(coords, {
            iconCaption: 'search...'
        }, {
            preset: 'islands#violetDotIconWithCaption',
            draggable: true
        });
    }

    // Coords
    function getAddress(coords) {
        myPlacemark.properties.set('iconCaption', 'поиск...');
        ymaps.geocode(coords).then(function (res) {
            var firstGeoObject = res.geoObjects.get(0);

            myPlacemark.properties
                .set({
                    // We form a line with data about the object.
                    iconCaption: [
                        firstGeoObject.geometry.getCoordinates(),
                    ].filter(Boolean).join(', '),
                    // We set the line with the object address as the balloon content.
                    balloonContent: firstGeoObject
                });
            document.querySelector(".coords").textContent = firstGeoObject.geometry.getCoordinates();
        });
    }
}
body, .mailForm {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
}

input, textarea {
    font-size: 14px;
    margin: 10px 0 0 0;
    width: 350px;
    resize: none;
}
.mailForm__map {
    margin-top: 10px;
}
button {
    margin: 10px 0 0 0;
    font-size: 14px;
    cursor: pointer;
}

.mailForm__comment {
    display: inline-block;
    height: 200px;
}

.mailForm__error, .mailForm__completed, .coords {
    display: none;
    color: red;
    font-size: 16px;
    font-weight: bold;
    margin-top: 10px;
}

.mailForm__completed {
    color: green;
    font-size: 20px;
}
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="style.css" rel="stylesheet">
    <title>Mail Form</title>
    <script src="https://api-maps.yandex.ru/2.1/?apikey=5200498b-0123-4796-1-bee4ea5473212&lang=ru_RU" type="text/javascript">
    </script>
</head>
<body>
    <div class="mailForm">
        <input class="mailForm__name" placeholder="Name" type="text" value="">
        <input class="mailForm__number" placeholder="Tel" type="tel" value="">
        <input class="mailForm__email" placeholder="Email" type="email" value="">
        <div id="map" class="mailForm__map" style="width: 100%; height: 200px">

        </div>
        <textarea class="mailForm__comment" maxlength="500" placeholder="Comment" type="text" value=""></textarea>
        <button onclick="viodChecker()">SEND</button>
        <div class="mailForm__error name-error">NAME ERROR</div>
        <div class="mailForm__error number-error">TEL ERROR</div>
        <div class="mailForm__error email-error">@ ERROR</div>
        <div class="mailForm__error map-error">COORDS ERROR</div>
        <div class="mailForm__completed">NICE!</div>
        <div class="coords"></div>
    </div>
    <script src="script.js"></script>
</body>
</html>

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

DRYing the ifs One option would be to use else, or even better, the conditional (ternary) operator instead of having two separate blocks for each validator:

errorName.style.display = name ? 'none' : 'block';
errorNumber.style.display = number ? 'none' : 'block';
errorEmail.style.display = email.includes('@') ? 'none' : 'block';
errorMap.style.display = Coords.textContent ? 'block' : 'none';

(You could also use a CSS class for this instead, and use classList.toggle and a second argument)

But for the inputs, rather than having these manual error divs, consider using the HTML to force validation instead. Put the inputs into a <form>, and then:

  • For the name and number, use the required attribute - the user's browser will tell them to fill out the fields
  • For the email, use the type="email" attribute, and the user's browser will validate the email address (more reliably than just checking for @s).

Div crutch Rather than using a <div> to populate the getCoordinates results, you can save in an outer variable, eg:

// top level
let coords;
// ...lots of code
      coords = firstGeoObject.geometry.getCoordinates();

Then rather than checking Coords.textContent, check the contents of the variable coords.

Other suggestions:

Always use const when you can - only use let when you must warn readers of the code that you may be reassigning the variable later in the code. 95% of variable declarations can be with const, usually.

On a similar note:

If you're writing in modern syntax (which you are, and you should!), never use var - var has the same problems as let, but also has issues with having unintuitive function scope instead of block scope, and of being automatically assigned to a property of the global object when on the top level.

Catch asynchronous errors, don't ignore them - currently, if .geocode throws, no indication will be given to the user, and they may well be confused. When dealing with a Promise, usually you'll want to follow a pattern like:

someProm
    .then((result) => {
        // do stuff with result
    })
    .catch((err) => {
        // there was an error, inform the user and maybe log it for debugging
    });

Avoid inline event handlers, they have too many problems to be worth using nowadays, including a demented scope chain and requiring global pollution. Instead, add the event listener using JavaScript instead, eg:

document.querySelector('.mailform > button').addEventListener('click', viodChecker);
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.