Skip to content

Commit

Permalink
refactor: create Form base class
Browse files Browse the repository at this point in the history
  • Loading branch information
hdev14 committed Feb 10, 2024
1 parent 8142878 commit da5b6e3
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"document": true,
"utils": true,
"Validator": true,
"grecaptcha": true
"grecaptcha": true,
"Form": true
},
"extends": "airbnb-base",
"parserOptions": {
Expand Down
16 changes: 15 additions & 1 deletion src/application/pages/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ <h1>{{title}}</h1>
</main>

<script>
new LoginForm().init();
new LoginForm(
document.getElementById('login-form'),
[
{
input_element: document.getElementById('email'),
error_message_element: document.getElementById('email-error-messages'),
rules: ['required', 'string', 'email']
},
{
input_element: document.getElementById('password'),
error_message_element: document.getElementById('password-error-messages'),
rules: ['required', 'string', 'min:8', 'password']
}
]
).init();
</script>
{{> _footer}}
1 change: 1 addition & 0 deletions src/application/pages/partials/_head.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

<!-- global scripts -->
<script type="application/javascript" src="https://unpkg.com/js-cookie@3.0.5/dist/js.cookie.min.js"></script>
<script type="application/javascript" src="/js/form.js"></script>

{{> components/links}}
{{> components/scripts}}
Expand Down
88 changes: 88 additions & 0 deletions src/application/public/js/form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// eslint-disable-next-line no-unused-vars
class Form {
/**
* @property {Object[]} fields
* @property {Element} fields.input_element
* @property {Element} fields.error_message_element
* @property {string[]} fields.rules
*/
fields = [];

/**
* @property {Element} form
*/
form;

/**
* @param {Element} form
* @param {Object[]} fields
* @param {Element} fields[].input_element
* @param {Element} fields[].error_message_element
*/
constructor(form, fields) {
this.form = form;
this.fields = fields;
}

init() {
this.fields.forEach(({ input_element, error_message_element, rules }) => {
input_element.addEventListener('blur', this.validateInput(
error_message_element,
input_element.getAttribute('name'),
rules,
).bind(this));
});

this.form.addEventListener('submit', this.submit.bind(this));
}

/**
*
* @returns {boolean}
*/
hasErrors() {
return this.fields.some(({ error_message_element }) => !!error_message_element.firstChild);
}

/**
*
* @param {Event} event
*/
submit(event) {
console.log(event);
throw new Error('Not implemented');
}

/**
* @param {Element} error_message_element
* @param {string} field_name
* @param {string[]} rules
*/
validateInput(error_message_element, field_name, rules) {
return function onBlur(e) {
utils.removeChildsFromParent(error_message_element);

const errors = Validator.setData({ [field_name]: e.target.value })
.setRule(field_name, rules)
.validate();

if (errors.length) {
this.#appendErrorMessages(errors[0].messages, error_message_element);
}
};
}

/**
*
* @param {string[]} error_messages
* @param {Element} element
*/
#appendErrorMessages(error_messages, element) {
error_messages.forEach((message) => {
const li = document.createElement('li');
const text = document.createTextNode(message);
li.appendChild(text);
element.appendChild(li);
});
}
}
57 changes: 4 additions & 53 deletions src/application/public/js/login_form.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,9 @@
// eslint-disable-next-line no-unused-vars
class LoginForm {
#login_form = document.getElementById('login-form');

#email_input = document.getElementById('email');

#email_error_messages_ul = document.getElementById('email-error-messages');

#password_input = document.getElementById('password');

#password_error_messages_ul = document.getElementById('password-error-messages');

init() {
this.#email_input.addEventListener('blur', this.#validateEmail.bind(this));
this.#password_input.addEventListener('blur', this.#validatePassword.bind(this));
this.#login_form.addEventListener('submit', this.#submit.bind(this));
}

static #appendErrorMessages(error_messages, element) {
error_messages.forEach((message) => {
const li = document.createElement('li');
const text = document.createTextNode(message);
li.appendChild(text);
element.appendChild(li);
});
}

#validateEmail(e) {
utils.removeChildsFromParent(this.#email_error_messages_ul);

const errors = Validator.setData({ email: e.target.value })
.setRule('email', ['required', 'string', 'email'])
.validate();

if (errors.length) {
LoginForm.#appendErrorMessages(errors[0].messages, this.#email_error_messages_ul);
}
}

#validatePassword(e) {
utils.removeChildsFromParent(this.#password_error_messages_ul);

const errors = Validator.setData({ password: e.target.value })
.setRule('password', ['required', 'string', 'min:8', 'password'])
.validate();

if (errors.length) {
LoginForm.#appendErrorMessages(errors[0].messages, this.#password_error_messages_ul);
}
}

#submit(e) {
class LoginForm extends Form {
submit(e) {
e.preventDefault();

if (this.#email_error_messages_ul.firstChild && this.#password_error_messages_ul.firstChild) {
if (this.hasErrors()) {
return;
}

Expand All @@ -71,7 +22,7 @@ class LoginForm {
});

if (response.status === 204) {
this.#login_form.submit();
this.form.submit();
}
});
}
Expand Down
30 changes: 25 additions & 5 deletions src/application/public/js/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ const RULE_FUNCTIONS = {
password: (value) => (
value !== undefined
&& typeof value === 'string'
&& value.length <= 8
&& !(
value.includes('!')
|| value.includes('@')
Expand Down Expand Up @@ -110,15 +109,30 @@ class Validator {
this.#data = data;
}

/**
*
* @param {Object} data
* @returns {Validator}
*/
static setData(data) {
return new Validator(data);
}

/**
*
* @param {string} field
* @param {string[]} rule
* @returns {Validator}
*/
setRule(field, rule) {
this.#rule_map.set(field, rule);
return this;
}

/**
*
* @returns {Object[]}
*/
validate() {
const entries = this.#rule_map.entries();

Expand All @@ -131,18 +145,24 @@ class Validator {
messages.push(`O campo ${fieldName} não é válido.`);
}
} else {
messages.push(...this.validateByArray(rule, field));
messages.push(...this.#validateByArray(rule, field));
}

if (messages.length > 0) {
this.addError({ field: fieldName, messages });
this.#addError({ field: fieldName, messages });
}
}

return this.#errors;
}

validateByArray(rule, field) {
/**
*
* @param {*} rule
* @param {*} field
* @returns {string[]}
*/
#validateByArray(rule, field) {
const messages = [];

for (let i = 0, len = rule.length; i < len; i += 1) {
Expand All @@ -159,7 +179,7 @@ class Validator {
return messages;
}

addError(error) {
#addError(error) {
const index = this.#errors.findIndex((e) => e.field === error.field);

if (index !== -1) {
Expand Down

0 comments on commit da5b6e3

Please sign in to comment.