Skip to content

Instantly share code, notes, and snippets.

@embarq
Created April 16, 2020 17:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save embarq/9e8221a1a8091de8765f9f63b7882cc0 to your computer and use it in GitHub Desktop.
Save embarq/9e8221a1a8091de8765f9f63b7882cc0 to your computer and use it in GitHub Desktop.
Forms
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>DOM task: Form model</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<style>
.app-container {
width: 420px;
padding-top: 3rem;
}
</style>
</head>
<body>
<div class="container app-container">
<form action="">
<p class="form-group px-3">
<label for="email-control">Email</label>
<input id="email-control" type="email" placeholder="example@org.com" class="form-control" />
</p>
<p class="form-group px-3">
<label for="username-control">Username</label>
<input type="text" id="username-control" class="form-control" />
</p>
</form>
</div>
<script src="main.js"></script>
</body>
</html>
class EventEmitter {
constructor() {
this.handlers = [];
}
subscribe(eventHandler) {
this.handlers.push(eventHandler);
}
emit(data) {
this.handlers.forEach(handler => handler(data));
}
}
class Validator {
validate() {
throw new Error('Not implemented');
}
}
class RequiredValidator extends Validator {
validate(value) {
return value != null && (typeof value === 'string' && value.trim().length > 0);
}
}
class MinLengthValidator extends Validator {
constructor(minValue) {
super();
if (!Number.isFinite(minValue)) {
throw new Error('minValue is required argument');
}
this.minValue = minValue;
}
validate(value) {
return value.length > this.minValue;
}
}
class FormControl {
constructor(id, initialValue = '', validators) {
this.value = initialValue;
this.validators = validators;
this.status = false;
this.statusChange = new EventEmitter();
// TODO: show hints about validation state
const inputElem = document.getElementById(id);
inputElem.addEventListener('change', (event) => {
this.status = this.validators.every(validator => {
if (!(validator instanceof Validator)) {
throw new Error('Invalid validator');
}
return validator.validate(event.target.value);
});
this.statusChange.emit(this.status);
});
this.statusChange.subscribe(status => {
if (status === false) {
const hintElem = document.createElement('p');
hintElem.className = 'text-danger';
hintElem.innerText = 'Value is invalid';
hintElem.id = 'hint-for-' + inputElem.id;
inputElem.parentElement.appendChild(hintElem);
inputElem.classList.toggle('is-invalid');
} else {
const hintElem = inputElem.parentElement.querySelector('#hint-for-' + inputElem.id);
if (hintElem != null) {
inputElem.classList.toggle('is-invalid');
hintElem.remove();
}
}
});
}
}
class FormGroup {
constructor(id, controls) {
this.status = false;
this.statusChange = new EventEmitter();
this.controlsStatus = { };
for (let control of controls) {
control.statusChange.subscribe(status => {
this.controlsStatus[control.id] = status;
this.status = Object.values(this.controlsStatus).every(controlStatus => (controlStatus === true));
this.statusChange.emit(this.status);
});
}
}
}
window.addEventListener('DOMContentLoaded', () => {
const registerForm = new FormGroup('', [
new FormControl('email-control', '', [
new RequiredValidator()
]),
new FormControl('username-control', '', [
new RequiredValidator(),
new MinLengthValidator(3)
])
]);
registerForm.statusChange.subscribe((formStatus) => {
console.log('Register form status is', formStatus);
});
// const emailControl = new FormControl('email-control', '', [
// new RequiredValidator()
// ]);
// const usernameControl = new FormControl('username-control', '', [
// new RequiredValidator(),
// new MinLengthValidator(3)
// ]);
// emailControl.statusChange.subscribe(status => {
// console.log('Email control status is', status);
// });
// usernameControl.statusChange.subscribe(status => {
// console.log('Username control status is', status);
// });
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment