Task: there is an order form, we need to add validation of required fields:
- recipient name: Latin / Cyrillic letters and spaces
- phone: in the format of the example (parentheses, hyphen, numbers)
- street: Latin / Cyrillic letters and spaces
- house: numbers, hyphen, slash, letters (after number)
- apartment: number
- email: Latin letters, at sign, dots, hyphens
Upon losing focus on a field if wrong characters were entered - we should show a red border and text below / above the field.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
.red { color: red; }
.tooltip { color: grey; font-size: 12px; }
.call-to-action { font-size: 13px; font-style: italic; }
.granted { border: 2px solid green; }
.denied { border: 2px solid red; }
.error { background-color: red; color: white; font-size: 12px; font-weight: bold; padding: 2px; }
#comment, .hide { display: none; }
a {
text-decoration: none;
border-bottom: 1px dashed #1F7EDB;
color: #1F7EDB;
}
input[type=submit] {
background-color: green;
border: 0;
color: white;
font-weight: bold;
margin-right: 35px;
padding: 10px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
input[type=reset] {
background-color: #DF0400;
border: 0;
color: white;
padding: 10px;
font-weight: bold;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
</style>
<h2>Order Checkout</h2>
<hr width="500" align="left">
<form>
<input type="hidden" name="date" value="11 September 2013">
<input type="hidden" name="time" value="20:55">
<table border=0>
<tr>
<td width=160>
<label for="client">Recipient Name</label>
</td>
<td width=400>
<input type="text" name="client" id="client" placeholder="Name" maxlength="20"><span class="red">*</span>
</td>
</tr>
<tr>
<td>
<label for="phone">Phone</label>
</td>
<td>
<input type="text" name="phone" id="phone" placeholder="Phone number" maxlength="15"><span class="red">*</span>
<select name="phone_type">
<option value="mobile">Mobile</option>
<option value="home">Home</option>
<option value="work">Work</option>
</select>
<br>
<span class="tooltip">For example, (012) 345-67-89</span>
</td>
</tr>
<tr>
<td>
<label for="city">City</label>
</td>
<td>
<select name="city" id="city">
<option value="empty">choose a city</option>
<option value="kyiv">Kyiv</option>
<option value="odessa">Odesa</option>
<option value="lviv">Lviv</option>
<option value="dnipro">Dnipro</option>
</select>
<span class="red">*</span>
</td>
</tr>
<tr>
<td>
<label for="delivery">Delivery Method</label>
</td>
<td>
<select name="delivery" id="delivery" disabled>
<option value="empty">choose a delivery method</option>
<option value="courier">Courier</option>
<option value="self">Pickup</option>
</select>
<img valign="middle" src="http://s.cdpn.io/62886/info.png" alt="info" />
</td>
</tr>
<tr class="address-block">
<td>
<label for="address">Recipient Address</label>
</td>
<td>
<table>
<tr>
<td>
<input type="text" id="street" name="street" class="address" placeholder="Street" maxlength="30" disabled>
</td>
<td>
<input type="text" id="house" name="house" placeholder="House" class="address" size="5" maxlength="10" disabled>
</td>
<td>
<input type="text" id="app" name="app" placeholder="Apartment" class="address" maxlength="10" disabled>
</td>
</tr>
<tr>
<td class="tooltip">
Street
</td>
<td class="tooltip">
House
</td>
<td class="tooltip">
Apartment
</td>
</tr>
</table>
</td>
</tr>
<tr class="address-block">
<td colspan=2>
<textarea name="info" id="info" cols="55" rows="8" disabled>
Delivery within the city is free for orders over 1500 UAH. For smaller orders, the delivery cost is 35 UAH.
Goods from the "Active recreation and tourism", "Home, garden" and "Children's world" sections are delivered for free for orders starting from 500 UAH.
Goods from the "Household appliances" and "Interior" sections are delivered for free in Kyiv for orders starting from 800 UAH.
</textarea>
</td>
</tr>
<tr>
<td>
<label for="payment">Payment</label>
</td>
<td>
<select name="payment" id="payment">
<option value="cash">Cash</option>
<option value="noncash">Cashless</option>
<option value="credit6">Credit "6"</option>
<option value="credit12">Credit "12"</option>
<option value="credit24">Credit "24"</option>
</select>
<img valign="middle" src="http://s.cdpn.io/62886/info.png" alt="info" />
</td>
</tr>
<tr>
<td>
<label for="email">Email address</label>
<br>
<span class="tooltip">To track order status</span>
</td>
<td>
<input type="text" id="email" name="email" size="40" placeholder="Email" maxlength="30">
<br>
<span class="call-to-action">Be the first to know about special offers, discounts and new items</span>
</td>
</tr>
<tr>
<td colspan=2>
<a href="#" id="comment-link" class="call-to-action">Add a comment to the order</a>
<br>
<div id="comment">
<textarea name="comment" cols="55" rows="5" maxlength="512"></textarea>
<br>
<span class="tooltip">Provide a comment no longer than 512 characters</span>
</div>
</td>
</tr>
<tr>
<td colspan=2>
<input type="checkbox" name="present" id="present">
<label for="present">For a gift</label>
<img valign="middle" src="http://s.cdpn.io/62886/info.png" alt="info" />
</td>
</tr>
<tr>
<td colspan=2>
<input type="submit" value="Confirm order">
<input type="reset" value="Clear data">
<br>
<span class="tooltip">
By confirming the order, I agree <br>with the user agreement <img valign="middle" src="http://s.cdpn.io/62886/info.png" alt="info" />
</span>
</td>
</tr>
</table>
</form>
<script>
window.onload = onLoad;
function onLoad () {
var client = document.getElementById("client");
var phone = document.getElementById("phone");
var email = document.getElementById("email");
var city = document.getElementById("city");
var street = document.getElementById("street");
var house = document.getElementById("house");
var appartment = document.getElementById("app");
var delivery = document.getElementById("delivery");
var commentLink = document.getElementById("comment-link");
var commentArea = document.getElementById("comment");
if (client && phone && email) {
client.onchange = onClientChange;
phone.onchange = onPhoneChange;
email.onchange = onEmailChange;
}
if (city && delivery) {
city.onchange = onCityChange;
delivery.onchange = onDeliveryChange;
}
if (street && house && appartment) {
street.onchange = onStreetChange;
house.onchange = onHouseChange;
appartment.onchange = onAppartmentChange;
}
if (commentLink && commentArea) {
commentLink.onclick = toggleCommentArea;
}
function grantDeny (element, regexp, errorMessage) {
var value = element.value;
console.log(value);
if (regexp.test(value)) {
element.classList.remove("denied");
element.classList.add("granted");
console.log(element.className);
} else {
element.classList.remove("granted");
element.classList.add("denied");
console.log(element.className);
if ((element.previousSibling.nodeType == 3) || (element.previousSibling.className != "error")) {
var msgElem = document.createElement('span');
msgElem.className = "error";
msgElem.innerHTML = errorMessage + "
";
element.parentNode.insertBefore(msgElem, element);
}
}
}
function onClientChange () {
var element = this;
var errorMessage = " Name specified incorrectly ";
var regexp = /^[А-Я]{0,1}[а-я]{1,15}( [А-Я]{0,1}[а-я]{1,15}){0,1}$|^[A-Z]{0,1}[a-z]{1,15}( [A-Z]{0,1}[a-z]{1,15}){0,1}$/; // Only pass Latin or Cyrillic letters and a space between the first and second word (if there is a second word). Both words can start with a capital letter
grantDeny(element, regexp, errorMessage);
}
function onPhoneChange () {
var element = this;
var regexp = /^\([0-9]{3}\) [0-9]{3}-[0-9]{2}-[0-9]{2}$/; // Pass number strictly in format (012) 345-67-89
var errorMessage = " Number specified incorrectly ";
grantDeny(element, regexp, errorMessage);
}
function onEmailChange () {
var element = this;
var regexp = /^([a-z0-9_-]{1,15}\.){0,3}[a-z0-9_-]{1,15}@[a-z0-9_-]{1,15}\.[a-z]{2,6}$/; // Pass up to 15 characters a-z0-9_- before the at sign, also it can be up to 4 words separated by dots. Then the at sign and domain name (from 1 to 15 characters). Then the domain zone - from 2 to 6 Latin letters
var errorMessage = " Email specified incorrectly ";
grantDeny(element, regexp, errorMessage);
}
function onCityChange () {
var value = this.value;
if (value !== "empty") {
delivery.disabled = false;
this.classList.remove("denied");
if (delivery.value === "courier") {
changeAddressState(false);
}
} else {
delivery.disabled = true;
changeAddressState(true);
this.classList.add("denied");
}
}
function onDeliveryChange () {
var value = this.value;
var state = false;
var addressBlock = document.querySelector("tr.address-block");
if (value !== "courier") {
addressBlock.classList.add("hide");
addressBlock.nextElementSibling.classList.add("hide");
state = true;
changeAddressState(state);
} else {
addressBlock.classList.remove("hide");
addressBlock.nextElementSibling.classList.remove("hide");
changeAddressState(state);
}
}
function changeAddressState (state) {
var inputs = document.querySelectorAll(".address");
var len = inputs.length;
var i;
console.log(inputs);
for (i = 0; i < len; i++) {
inputs[i].disabled = state;
}
}
function onStreetChange () {
var element = this;
var regexp = /^[а-яА-Я0-9-\. ]{0,30}$|^[a-zA-Z0-9-\. ]{0,30}$/; // Pass Latin or Cyrillic letters, numbers, hyphens, spaces and dots
var errorMessage = " Street specified incorrectly ";
grantDeny(element, regexp, errorMessage);
}
function onHouseChange() {
var element = this;
var regexp = /^[0-9-\/ ]{0,5}[а-яА-Я]{0,1}[ -]{0,1}[0-9]{0,2}$|^[0-9-\/ ]{0,5}[a-zA-Z]{0,1}[ -]{0,1}[0-9]{0,2}$/; // Pass from 0 to 5 numbers (possibly with slash and spaces), then 1 Latin or Cyrillic letter (if present), then space or hyphen (if present) and 2 numbers if they exist)
var errorMessage = " House specified incorrectly ";
grantDeny(element, regexp, errorMessage);
}
function onAppartmentChange () {
var element = this;
var regexp = /^[0-9]{0,10}$/; // Pass only numbers
var errorMessage = " Apartment specified incorrectly ";
grantDeny(element, regexp, errorMessage);
}
function toggleCommentArea () {
var style = commentArea.style;
if (style.display === "block") {
style.display = "none";
} else {
style.display = "block";
}
}
}
</script>
</body>
</html>