From d2fe244e048ca7a2c9f161d6b045f920decbe143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Jurmanovi=C4=87?= Date: Sat, 12 Jun 2021 11:54:13 +0200 Subject: [PATCH] added form validators --- package.json | 2 +- src/common/core/BaseElement/BaseElement.ts | 4 +- src/common/core/Validator/Validator.ts | 86 +++++++ src/common/index.ts | 2 + .../pages/BasePageElement/BasePageElement.ts | 2 +- .../app-dropdown/AppDropdownElement.ts | 139 ++++++------ src/components/app-form/AppFormElement.ts | 33 ++- src/components/app-link/AppLinkElement.ts | 2 +- src/components/app-loader/AppLoaderElement.ts | 2 +- src/components/app-menu/AppMenuElement.ts | 4 +- .../app-pagination/AppPaginationElement.ts | 2 +- .../circle-loader/CircleLoaderElement.ts | 2 +- .../input-field/InputFieldElement.ts | 51 ++--- src/components/menu-item/MenuItemElement.ts | 2 +- .../wallet-header/WalletHeaderElement.ts | 11 +- src/core/store/AuthStore.ts | 1 - src/core/utils/find-method.ts | 2 +- src/core/utils/index.ts | 4 + src/core/utils/library.ts | 3 + src/core/utils/templating.ts | 3 + src/core/utils/validator.ts | 25 +++ .../initial-layout/InitialLayoutElement.ts | 2 +- src/layouts/menu-layout/MenuLayoutElement.ts | 2 +- src/pages/history-page/HistoryPageElement.ts | 2 +- src/pages/home-page/HomePageElement.ts | 2 +- src/pages/login-page/LoginPageElement.ts | 10 +- src/pages/not-found/NotFoundElement.ts | 2 +- .../register-page/RegisterPageElement.ts | 30 ++- .../TransactionCreateElement.ts | 2 +- .../wallet-create/WalletCreateElement.ts | 2 +- src/pages/wallet-list/WalletListElement.ts | 2 +- src/pages/wallet-page/WalletPageElement.ts | 2 +- src/styles/app-dropdown/app-dropdown.scss | 212 +++++++++--------- src/styles/input-field/index.scss | 1 + src/styles/input-field/input-field.scss | 8 + src/styles/main.scss | 23 +- webpack.config.js | 3 +- yarn.lock | 4 +- 38 files changed, 424 insertions(+), 267 deletions(-) create mode 100644 src/common/core/Validator/Validator.ts create mode 100644 src/core/utils/library.ts create mode 100644 src/core/utils/templating.ts create mode 100644 src/core/utils/validator.ts create mode 100644 src/styles/input-field/index.scss create mode 100644 src/styles/input-field/input-field.scss diff --git a/package.json b/package.json index 8980f88..17b1676 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@github/catalyst": "^1.1.3", - "lit-html": "^1.4.1", + "core/utils": "^1.4.1", "validator": "^13.6.0" }, "devDependencies": { diff --git a/src/common/core/BaseElement/BaseElement.ts b/src/common/core/BaseElement/BaseElement.ts index ecce741..eb738d3 100644 --- a/src/common/core/BaseElement/BaseElement.ts +++ b/src/common/core/BaseElement/BaseElement.ts @@ -1,4 +1,4 @@ -import { html, render, TemplateResult } from 'lit-html'; +import { html, render, TemplateResult } from 'core/utils'; import { AppLoaderElement, AppMainElement, AppModalElement, AppRootElement } from 'components/'; import { AppService, RouterService } from 'core/services'; import { AuthStore } from 'core/store'; @@ -71,7 +71,7 @@ class BaseElement extends HTMLElement { }); }; - render = (): TemplateResult | Temp => { + render = (): TemplateResult => { return html``; }; diff --git a/src/common/core/Validator/Validator.ts b/src/common/core/Validator/Validator.ts new file mode 100644 index 0000000..45e5acd --- /dev/null +++ b/src/common/core/Validator/Validator.ts @@ -0,0 +1,86 @@ +import { AppFormElement } from 'components/'; +import { validatorErrors } from 'core/constants'; +import { firstUpper, validator } from 'core/utils'; + +class Validator { + public _error: string; + public _valid: boolean; + constructor(public input: any, public form: AppFormElement, public rules: string) {} + + get value() { + return this.input?._value; + } + + get name() { + return this.input?.name; + } + + get error() { + return this._error; + } + + set error(error) { + this._error = error; + } + + get valid() { + return this._valid; + } + + set valid(error) { + this._valid = error; + } + + validate = () => { + const rules = this.rules?.split('|').filter((a) => a); + const value = this.value; + const validArr = rules + .slice() + .reverse() + .map((rule) => { + let args = []; + if (rule.includes('[') && rule.includes(']')) { + const begSep = rule.lastIndexOf('['); + const endSep = rule.lastIndexOf(']'); + + args = rule + .slice(begSep + 1, endSep) + .split(',') + .map((arg: string) => { + if (this.form && arg?.includes?.('field')) { + const begBr = arg.lastIndexOf('('); + const endBr = arg.lastIndexOf(')'); + const field = arg.slice(begBr + 1, endBr); + + return this.form?.values[field]; + } + }); + rule = rule.slice(0, begSep); + } + let validRule = validator?.[rule]; + let ruleArray = validRule ? Array.isArray(validRule) : false; + let valid = true; + + if (validRule) { + if (ruleArray) { + valid = validRule?.[0]?.(value, ...args); + } else { + valid = validRule?.(value, ...args); + } + } + if (!valid) { + const error = validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString())); + this.error = ruleArray ? validRule?.[1]?.replaceAll('{- name}', firstUpper(this.name?.toString())) : error; + } + return valid; + }); + const _return = validArr?.includes(false); + if (_return) { + this.error = null; + } + this.valid = !_return; + return !_return; + }; +} + +export default Validator; diff --git a/src/common/index.ts b/src/common/index.ts index f769514..d3e4e76 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,4 +1,6 @@ export { default as BaseElement } from './core/BaseElement/BaseElement'; +export { default as Validator } from './core/Validator/Validator'; + export * from './layouts'; export * from './components'; export * from './pages'; diff --git a/src/common/pages/BasePageElement/BasePageElement.ts b/src/common/pages/BasePageElement/BasePageElement.ts index 8655bf3..f998dc5 100644 --- a/src/common/pages/BasePageElement/BasePageElement.ts +++ b/src/common/pages/BasePageElement/BasePageElement.ts @@ -1,5 +1,5 @@ import { attr } from '@github/catalyst'; -import { html, render } from 'lit-html'; +import { html, render } from 'core/utils'; import { BaseElement } from 'common/'; import { isTrue } from 'core/utils'; diff --git a/src/components/app-dropdown/AppDropdownElement.ts b/src/components/app-dropdown/AppDropdownElement.ts index ea1f397..4165923 100644 --- a/src/components/app-dropdown/AppDropdownElement.ts +++ b/src/components/app-dropdown/AppDropdownElement.ts @@ -1,10 +1,10 @@ import { attr, controller, target } from '@github/catalyst'; -import { findMethod, firstUpper } from 'core/utils'; -import { html } from 'lit-html'; +import { closest, findMethod, firstUpper } from 'core/utils'; +import { html } from 'core/utils'; import randomId from 'core/utils/random-id'; -import validator from 'validator'; import { validatorErrors } from 'core/constants'; -import { BaseComponentElement } from 'common/'; +import { BaseComponentElement, Validator } from 'common/'; +import { AppFormElement } from 'components/app-form/AppFormElement'; @controller class AppDropdownElement extends BaseComponentElement { @@ -13,12 +13,12 @@ class AppDropdownElement extends BaseComponentElement { @attr rules: string; @target main: HTMLElement; @target inp: HTMLElement; + @target dropdowncontainer: HTMLElement; @attr displaykey: string = 'name'; @attr valuekey: string = 'id'; @attr fetch: string; - fetchFunc: any; + @closest appForm: AppFormElement; - error: boolean; errorMessage: string; searchPhrase: string; @@ -32,10 +32,56 @@ class AppDropdownElement extends BaseComponentElement { totalItems: number; page: number = 1; rpp: number = 30; + validator: Validator; constructor() { super(); } + + updateCallback = () => { + this.dropdowncontainer?.scrollIntoView(); + }; + + public elementConnected = (): void => { + this.validator = new Validator(this, this.appForm, this.rules); + this.randId = `${name}${randomId()}`; + this.update(); + + const options = { + rpp: this.rpp, + page: this.page, + }; + this.getItems(options); + }; + + attributeChangedCallback(): void { + this.update(); + } + + setError = (error) => { + this.validator.error = error; + }; + + get error(): string { + return this.validator?.error; + } + + get isValid(): boolean { + return this.validator?.valid; + } + + get required(): boolean { + return this.rules.includes('required'); + } + + get _value() { + return this.value; + } + + validate = (): boolean => { + return this.validator.validate(); + }; + getItems = async (options?: any): Promise => { if (typeof this.fetchFunc !== 'function') return; try { @@ -68,8 +114,6 @@ class AppDropdownElement extends BaseComponentElement { return value == item[valuekey]; }); - console.log(item, value, valuekey); - return item; } @@ -83,61 +127,16 @@ class AppDropdownElement extends BaseComponentElement { return values; } - public elementConnected = (): void => { - this.randId = `${name}${randomId()}`; - this.fetchFunc = findMethod(this.fetch, this.appMain); - this.update(); + get fetchFunc() { + return findMethod(this.fetch, this.appMain); + } - const options = { - rpp: this.rpp, - page: this.page, - }; - this.getItems(options); + setOpen = (isOpen) => { + this.isOpen = isOpen; }; - attributeChangedCallback(): void { - this.update(); - } - - get valid(): boolean { - return !!this.error; - } - - get required(): boolean { - return this.rules.includes('required'); - } - - validate(): boolean { - let _return = true; - const rules = this.rules?.split('|').filter((a) => a); - const value = (this.inp as HTMLSelectElement)?.value; - rules - .slice() - .reverse() - .forEach((rule) => { - let valid = true; - if (rule == 'required') { - if (value === '') valid = false; - } else { - if (validator.hasOwnProperty(rule)) { - valid = validator?.[rule]?.(value); - } - } - if (!valid) { - const error = validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString())); - _return = false; - this.error = error; - } - }); - if (_return) { - this.error = null; - } - this.update(); - return _return; - } - openDropdown = () => { - this.isOpen = true; + this.setOpen(true); }; stopPropagation = (e) => { @@ -146,24 +145,24 @@ class AppDropdownElement extends BaseComponentElement { toggleDropdown = () => { const isOpen = this.isOpen; - this.isOpen = !isOpen; + this.setOpen(!isOpen); }; itemSelected = (e) => { const value = (e.target as HTMLSpanElement).getAttribute('data-value'); - this.value = value; - this.isOpen = false; + this.setOpen(false); + this.setValue(value); + this.appForm?.inputChange(e); }; - get _value() { - return this.value; - } + setValue = (value) => { + this.value = value; + this.update(); + }; render = () => { const { label, error, errorMessage, isOpen, searchPhrase, items, selectedItem, displaykey, valuekey } = this; - console.log(isOpen); - const renderItem = (item) => { return html`