Form validation

Run a series of validation tasks against each form value.

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://fonts.googleapis.com/css?family=Roboto"></script>
<div class="loading" data-loading>
  <div class="content">
    <i class="fa fa-spinner fa-pulse"></i>
    Validating ..
  </div>
</div>

<div class="output js-hide" data-output></div>

SCSS

html, body {
  margin: 0;
  padding: 0;
  background: whitesmoke;
  color: #383838;
  font-family: 'Roboto', sans-serif;
}

.loading {
  top: 0;
  left: 0;
  z-index: 9999;
  position: absolute;
  width: 100%;
  height: 100%;
  color: #787878;
  background: whitesmoke;
  .content {
    text-align: center;
    width: 75%;
    margin: 10% auto;
  }
}

.output {
  background: white;
  padding: 15px;
  width: 75%;
  margin: 10% auto;
  border-bottom: 1px solid #dadada;
  border-radius: 3px;
  pre {
    border-radius: 2px;
    border-top: 1px solid #dadada;
    background: #fafafa;
    padding: 10px 15px;
    margin: 15px 0 0 0;
    box-shadow: inset 0 1px 3px rgba(0,0,0,.075);
  }
}

.js-hide { display: none }
.text-error { color: #f44336 }
.text-complete { color: #4CAF50 }

Babel + JSX

const formData = {
	name: 'Joe Bloggs', email: '[email protected]' }

/* ================================================================================================================= */

// validation function
const validatorFn = formData => new Promise((resolve, reject) => {
	let arr = []
  for (var field in formData) {
  	if (!config.hasOwnProperty(field)) return reject(`${field} has no validation tasks.`)
    arr.push(config[field].map(cb => cb(formData[field])))
  }
  const tasks = arr.reduce((a, b) => a.concat(b))
  Promise.all(tasks)
  .then(res => resolve(res))
  .catch(err => reject(err))
})

// get element by data attribute
const $$ = data => $('[data-' + data + ']')

// loading and output
var $loading = $$('loading')
var $output = $$('output')

// validation config
const config = {
	name: [
  	val => new Promise((resolve, reject) => resolve(val)),
    val => new Promise((resolve, reject) => resolve(val))
  ],
	username: [
  	val => new Promise((resolve, reject) => resolve(val)),
    val => new Promise((resolve, reject) => resolve(val))
  ],
  email: [
  	// If I wanted to enforce, something whereby username
    // must match [username]@example.com, I will need access
    // to the username value here
    val => new Promise((resolve, reject) => resolve('ok')),
    val => new Promise((resolve, reject) => setTimeout(() => {
      reject(`${val} already is exists.`) // simulate a HTTP request
    }, 2000))
  ]
}

// launch the validations
validatorFn(formData)
.then(res => {
	$output.html([
  	'<span class="text-complete">',
    '<i class="fa fa-check"></i>',
    '&nbsp;Success',
    '</span>',
    '<pre>',
    'All validations passed!',
    '</pre>'
  ].join(''))
  $loading.fadeOut(() => $output.fadeIn())
})
.catch(err => {
	$output.html([
  	'<span class="text-error">',
    '<i class="fa fa-exclamation-triangle"></i>',
    '&nbsp;Failure',
    '</span>',
    '<pre>',
    err,
    '</pre>'
  ].join(''))
  $loading.fadeOut(() => $output.fadeIn())
})