import Modifier from 'ember-modifier'; import { action } from '@ember/object'; class ValidationError extends Error {} export default class ValidateModifier extends Modifier { item = null; hash = null; validate(value, validations = {}) { if (Object.keys(validations).length === 0) { return; } const errors = {}; Object.entries(this.hash.validations) // filter out strings, for now these are helps, but ain't great if someone has a item.help .filter(([key, value]) => typeof value !== 'string') .forEach(([key, item]) => { // optionally set things for you if (this.item) { this.item[key] = value; } (item || []).forEach((validation) => { const re = new RegExp(validation.test); if (!re.test(value)) { errors[key] = new ValidationError(validation.error); } }); }); const state = this.hash.chart.state || {}; if (state.context == null) { state.context = {}; } if (Object.keys(errors).length > 0) { state.context.errors = errors; this.hash.chart.dispatch('ERROR', state.context); } else { state.context.errors = null; this.hash.chart.dispatch('RESET', state.context); } } @action reset(e) { if (e.target.value.length === 0) { const state = this.hash.chart.state; if (!state.context) { state.context = {}; } if (!state.context.errors) { state.context.errors = {}; } Object.entries(this.hash.validations) // filter out strings, for now these are helps, but ain't great if someone has a item.help .filter(([key, value]) => typeof value !== 'string') .forEach(([key, item]) => { if (typeof state.context.errors[key] !== 'undefined') { delete state.context.errors[key]; } }); if (Object.keys(state.context.errors).length === 0) { state.context.errors = null; this.hash.chart.dispatch('RESET', state.context); } } } async connect([value], _hash) { this.element.addEventListener('input', this.listen); this.element.addEventListener('blur', this.reset); if (this.element.value.length > 0) { await Promise.resolve(); if (this && this.element) { this.validate(this.element.value, this.hash.validations); } } } @action listen(e) { this.validate(e.target.value, this.hash.validations); } disconnect() { this.item = null; this.hash = null; this.element.removeEventListener('input', this.listen); this.element.removeEventListener('blur', this.reset); } didReceiveArguments() { const [value] = this.args.positional; const _hash = this.args.named; this.item = value; this.hash = _hash; if (typeof _hash.chart === 'undefined') { this.hash.chart = { state: { context: {}, }, dispatch: (state) => { switch (state) { case 'ERROR': _hash.onchange(this.hash.chart.state.context.errors); break; case 'RESET': _hash.onchange(); break; } }, }; } } didInstall() { this.connect(this.args.positional, this.args.named); } willRemove() { this.disconnect(); } }