UNPKG

@vkm-js/validation

Version:

An Alpinejs validation that accepts and handles simple Laravel rules and validates in the frontend.

191 lines (189 loc) 7.32 kB
// packages/validation/src/index.js function src_default(Alpine) { Alpine.data("validation", (rules = {}, showAsTooltip = true) => ({ rules, showAsTooltip, ruleHasAsterisk: function(name) { if (name.includes("*")) { return true; } return false; }, validateDropdown(name = null, value = null, id = null) { if (!name) { console.warn("When validating a dropdown the model attribute cannot be empty!"); return; } let el = document.getElementById(id); this.isValid(el); if (!value) { let message = "The field is required."; if (!this.showAsTooltip) { let error = document.getElementById(`error-${id}`); if (!error) { el.insertAdjacentHTML("beforeend", `<div id="error-${id}" class="invalid-feedback">${message}</div>`); } } else { el.setAttribute("x-tooltip.danger.show", message); } } else { this.isValid(el); } }, validate() { let submit_btn = document.body.querySelectorAll('form button[type="submit"]')[0], event = this.$event.target, name = this.$event.target.getAttribute("model") ?? this.$event.target.getAttribute("name"), value = this.$event.target.value, validation_rules = []; try { this.rules = JSON.parse(this.rules); } catch (e) { } this.isValid(event); validation_rules = this.rules[name]; if (this.ruleHasAsterisk(name)) { let asterisk_name = name.replace(/[0-9]/g, "*"); validation_rules = this.rules[asterisk_name]; } if (!validation_rules) { return; } if (validation_rules.includes("nullable") && (!value || value == 0)) { return; } submit_btn.classList.add("disabled"); let check_as_number = validation_rules.some((r) => ["numeric", "integer"].includes(r)), error_msg_ending = check_as_number ? "." : " characters."; for (let i = 0; i < validation_rules.length; i++) { let rule_title = validation_rules[i]; if (typeof rule_title === "string") { if (Object.hasOwn(this.check, rule_title) && !this.check[rule_title](value)) { this.isInvalid(event, this.messages[rule_title]); break; } else if (["min:", "max:", "lt:", "lte:", "gt:", "gte:"].some((t) => rule_title.includes(t))) { let [field, limit] = rule_title.split(":"); if (!this.check[field](value, limit, check_as_number)) { let message = this.messages[field](limit) + error_msg_ending; this.isInvalid(event, message); break; } } else if (rule_title.includes("between:")) { let [field, between] = rule_title.split(":"); let [min, max] = between.split(","); if (!this.check[field](value, [min, max], check_as_number)) { let message = this.messages[field]([min, max]) + error_msg_ending; this.isInvalid(event, message); break; } } } } if (this.isFormValid) { submit_btn.classList.remove("disabled"); } }, check: { required: function(value) { return !!value; }, numeric: function(value) { return !isNaN(value); }, integer: function(value) { return Number.isInteger(Number(value)); }, email: function(value) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); }, alpha: function(value) { return /^[a-zA-Z ]+$/.test(value); }, alpha_dash: function(value) { return /^[a-zA-Z-_]+$/.test(value); }, alpha_num: function(value) { return /^[a-zA-Z0-9]+$/.test(value); }, between: function(value, between, check_as_number = false) { return check_as_number ? Number(value) > Number(between[0]) && Number(value) < Number(between[1]) : value.length > Number(between[0]) && value.length < Number(between[1]); }, min: function(value, min, check_as_number = false) { return check_as_number ? Number(value) >= Number(min) : value.length >= Number(min); }, max: function(value, max, check_as_number = false) { return check_as_number ? Number(value) <= Number(max) : value.length <= Number(max); }, gt: function(value, limit, check_as_number = false) { return check_as_number ? Number(value) > Number(limit) : value.length > Number(limit); }, gte: function(value, limit, check_as_number = false) { return check_as_number ? Number(value) >= Number(limit) : value.length >= Number(limit); }, lt: function(value, limit, check_as_number = false) { return check_as_number ? Number(value) < Number(limit) : value.length < Number(limit); }, lte: function(value, limit, check_as_number = false) { return check_as_number ? Number(value) <= Number(limit) : value.length <= Number(limit); } }, messages: { required: "The field is required.", numeric: "The field must be a number.", integer: "The field must be an integer number.", email: "The field must be a valid email address.", alpha_dash: "The field under validation may contain alphabetic characters, numbers, dashes or underscores.", alpha_num: "The field may only contain letters and numbers.", between: function(between) { return `The field must be between ${between[0]} and ${between[1]}`; }, min: function(min) { return `The field must be at least ${min}`; }, max: function(max) { return `The field may not be greater than ${max}`; }, lt: function(limit) { return `The field must be less than ${limit}`; }, lte: function(limit) { return `The field must be less than or equal ${limit}`; }, gt: function(limit) { return `The field must be must be greater than ${limit}`; }, gte: function(limit) { return `The field must be must be greater than or equal ${limit}`; } }, isValid: function(event) { event.classList.add("is-valid"); event.classList.remove("is-invalid"); setTimeout(function() { event.classList.remove("is-valid"); }, 2e3); if (this.showAsTooltip) { event.removeAttribute("x-tooltip.danger.show"); event.removeAttribute("data-tooltip"); document.querySelectorAll(".tooltip").forEach((e) => e.remove()); } let error = document.getElementById(`error-${event.id}`); if (error) { error.remove(); } this.isFormValid = true; }, isInvalid: function(event, message) { event.classList.remove("is-valid"); event.classList.add("is-invalid"); if (!this.showAsTooltip) { document.getElementById(event.id).outerHTML += `<div id="error-${event.id}" class="invalid-feedback">${message}</div>`; } else { event.setAttribute("x-tooltip.danger.show", message); } this.isFormValid = false; }, isFormValid: true })); } // packages/validation/builds/module.js var module_default = src_default; export { module_default as default, src_default as validation };