Skip to content

Commit

Permalink
feat(): #66 add showSuccessLabels method
Browse files Browse the repository at this point in the history
  • Loading branch information
horprogs committed May 18, 2022
1 parent ed08c65 commit 9933a93
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 24 deletions.
3 changes: 3 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,9 @@ <h2>
<button type="button" class="btn btn-warning" id="example12_error-btn">
Show email error
</button>
<button type="button" class="btn btn-success" id="example12_success-btn">
Show email success
</button>
<button class="btn btn-primary btn-block" id="example12_submit-btn">
Submit
</button>
Expand Down
20 changes: 17 additions & 3 deletions site/documentation/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@
<li class="nav-item">
<a class="nav-link scrollto" href="#section-5-11">showErrors</a>
</li>
<li class="nav-item">
<a class="nav-link scrollto" href="#section-5-12"
>showSuccessLabels</a
>
</li>
<li class="nav-item section-title mt-3">
<a class="nav-link scrollto" href="#section-6">Rules</a>
</li>
Expand Down Expand Up @@ -717,7 +722,7 @@ <h1 class="docs-heading">
<header class="docs-header">
<h1 class="docs-heading">
Methods
<span class="docs-time">Last updated: 2022-03-18</span>
<span class="docs-time">Last updated: 2022-05-18</span>
</h1>
</header>
<section class="docs-section" id="section-5-1">
Expand Down Expand Up @@ -1053,14 +1058,21 @@ <h2 class="section-heading">showErrors</h2>
<p>For example:</p>
<pre><code class="language-html">.showErrors({ '#email': 'The email is invalid' })</code></pre>
</section>
<section class="docs-section" id="section-5-12">
<h2 class="section-heading">showSuccessLabels</h2>
<p>Method to show success labels programmatically</p>
<pre><code class="language-html">.showSuccessLabels(errors: {key: message})</code></pre>
<p>For example:</p>
<pre><code class="language-html">.showSuccessLabels({ '#email': 'The email looks good!' })</code></pre>
</section>

<!--//section-->
</article>
<article class="docs-article" id="section-6">
<header class="docs-header">
<h1 class="docs-heading">
Rules
<span class="docs-time">Last updated: 2022-03-16</span>
<span class="docs-time">Last updated: 2022-05-18</span>
</h1>
</header>
<section class="docs-intro">
Expand Down Expand Up @@ -1139,7 +1151,9 @@ <h1 class="docs-heading">
<td><code>validator</code></td>
<td>
Used for a custom validation. It should return a boolean
or a function which returns a Promise.
or a function which returns a Promise. To mark the field
as a valid, <code>true</code> should be passed to
<code>resolve</code> callback: <code>resolve(true)</code>
</td>
<td>
<code
Expand Down
20 changes: 20 additions & 0 deletions site/examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,13 @@ <h2>
>
Show email error
</button>
<button
type="button"
class="btn btn-success"
id="example12_success-btn"
>
Show email success
</button>
<button
class="btn btn-primary btn-block"
id="example12_submit-btn"
Expand All @@ -1593,6 +1600,11 @@ <h2>
fontSize: '14px',
color: '#dc3545',
},
successFieldCssClass: 'is-valid',
successLabelStyle: {
fontSize: '14px',
color: '#20b418',
},
focusInvalidField: true,
lockForm: true,
});
Expand All @@ -1605,6 +1617,14 @@ <h2>
});
});

document
.querySelector('#example12_success-btn')
?.addEventListener('click', () => {
validation.showSuccessLabels({
'#example12_name': 'The email looks good!',
});
});

validation
.addField('#example12_name', [
{
Expand Down
17 changes: 15 additions & 2 deletions src/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,13 +619,18 @@ const errorsContainer = (): void => {
});
};

const showErrors = (): void => {
const showMessages = (): void => {
const validation = new JustValidate('#show-errors-form', {
errorFieldCssClass: 'is-invalid',
errorLabelStyle: {
fontSize: '14px',
color: '#dc3545',
},
successFieldCssClass: 'is-valid',
successLabelStyle: {
fontSize: '14px',
color: '#20b418',
},
focusInvalidField: true,
lockForm: true,
});
Expand All @@ -638,6 +643,14 @@ const showErrors = (): void => {
});
});

document
.querySelector('#example12_success-btn')
?.addEventListener('click', () => {
validation.showSuccessLabels({
'#example12_name': 'The email looks good!',
});
});

validation
.addField('#example12_name', [
{
Expand All @@ -660,4 +673,4 @@ dateTextInput();
dateDateInput();
successLabel();
errorsContainer();
showErrors();
showMessages();
50 changes: 32 additions & 18 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
FilesRuleValueInterface,
ElemValueType,
CustomMessageFuncType,
ShowErrorsInterface,
ShowLabelsInterface,
} from './modules/interfaces';
import {
getDefaultFieldMessage,
Expand Down Expand Up @@ -761,7 +761,7 @@ class JustValidate {

return new Promise((resolve) => {
this.validateField(field, true).finally(() => {
this.clearFieldError(field);
this.clearFieldStyle(field);
this.clearFieldLabel(field);
this.renderFieldError(field);
resolve(!!this.fields[field].isValid);
Expand Down Expand Up @@ -1135,7 +1135,7 @@ class JustValidate {
this.successLabels[fieldName]?.remove();
}

clearFieldError(fieldName: string): void {
clearFieldStyle(fieldName: string): void {
const field = this.fields[fieldName];

const errorStyle =
Expand Down Expand Up @@ -1172,7 +1172,7 @@ class JustValidate {
);

for (const fieldName in this.fields) {
this.clearFieldError(fieldName);
this.clearFieldStyle(fieldName);
}

for (const groupName in this.groupFields) {
Expand Down Expand Up @@ -1461,19 +1461,13 @@ class JustValidate {
}
}

showErrors(errors: ShowErrorsInterface): void {
if (typeof errors !== 'object') {
throw Error(
'[showErrors]: Errors should be an object with key: value format'
);
}

Object.keys(errors).forEach((fieldName, i) => {
const error = errors[fieldName];
showLabels(fields: ShowLabelsInterface, isError: boolean): void {
Object.keys(fields).forEach((fieldName, i) => {
const error = fields[fieldName];
const field = this.fields[fieldName];

field.isValid = false;
this.clearFieldError(fieldName);
field.isValid = !isError;
this.clearFieldStyle(fieldName);
this.clearFieldLabel(fieldName);

this.renderFieldError(fieldName, error);
Expand All @@ -1484,15 +1478,35 @@ class JustValidate {
});
}

renderFieldError(fieldName: string, error?: string): void {
showErrors(fields: ShowLabelsInterface): void {
if (typeof fields !== 'object') {
throw Error(
'[showErrors]: Errors should be an object with key: value format'
);
}

this.showLabels(fields, true);
}

showSuccessLabels(fields: ShowLabelsInterface): void {
if (typeof fields !== 'object') {
throw Error(
'[showSuccessLabels]: Labels should be an object with key: value format'
);
}

this.showLabels(fields, false);
}

renderFieldError(fieldName: string, message?: string): void {
const field = this.fields[fieldName];

if (field.isValid) {
// we should not show success labels if there are async rules pending
if (!field.asyncCheckPending) {
const successLabel = this.createSuccessLabelElem(
fieldName,
field.successMessage,
message !== undefined ? message : field.successMessage!,
field.config
);
if (successLabel) {
Expand Down Expand Up @@ -1524,7 +1538,7 @@ class JustValidate {

const errorLabel = this.createErrorLabelElem(
fieldName,
error !== undefined ? error : field.errorMessage!,
message !== undefined ? message : field.errorMessage!,
field.config
);
this.renderFieldLabel(
Expand Down
2 changes: 1 addition & 1 deletion src/modules/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,6 @@ export interface TooltipInstance {

export type ElemValueType = boolean | string | FileList | null;

export interface ShowErrorsInterface {
export interface ShowLabelsInterface {
[field: string]: string;
}
111 changes: 111 additions & 0 deletions src/tests/showSuccessLabelsMethod.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { mockup } from './mockup';
import JustValidate from '../main';
import { Rules } from '../modules/interfaces';
import { waitFor } from '@testing-library/dom';
import {
clickBySelector,
getAllElemsByTestId,
getElem,
getElemByTestId,
} from '../utils/testingUtils';

describe('ShowSuccessLabels method', () => {
beforeEach(() => {
console.warn = jest.fn();
console.error = jest.fn();

document.body.innerHTML = mockup;
});

test('invalid configuration', async () => {
const validation = new JustValidate(document.querySelector('#form')!, {
testingMode: true,
});

validation.addField('#password', [
{
rule: 'required' as Rules,
},
]);

expect(() => {
// @ts-ignore
validation.showSuccessLabels(123);
}).toThrow();
});

test('should show success labels', async () => {
const validation = new JustValidate(document.querySelector('#form')!, {
testingMode: true,
});

validation.addField('#password', [
{
rule: 'required' as Rules,
},
]);

await clickBySelector('#submit-btn');
await waitFor(() => {
expect(getElem('#submit-btn')).toBeEnabled();
});

expect(getElemByTestId('error-label-#password')).toHaveTextContent(
'The field is required'
);

validation.showSuccessLabels({
'#password': 'Your password valid!',
});

await waitFor(() => {
expect(getElemByTestId('error-label-#password')).not.toBeInTheDocument();
});

expect(getElemByTestId('success-label-#password')).toHaveTextContent(
'Your password valid!'
);
});

test('should show empty success label', async () => {
const validation = new JustValidate(document.querySelector('#form')!, {
testingMode: true,
});

validation.addField('#password', [
{
rule: 'required' as Rules,
},
]);

validation.showSuccessLabels({
'#password': '',
});

await waitFor(() => {
expect(getElemByTestId('success-label-#password')).toHaveTextContent('');
});
});

test('should clear error before calling', async () => {
const validation = new JustValidate(document.querySelector('#form')!, {
testingMode: true,
});

validation.addField('#password', [
{
rule: 'required' as Rules,
},
]);

validation.showSuccessLabels({
'#password': 'The password is valid',
});

validation.showSuccessLabels({
'#password': 'The password is valid',
});

expect(getAllElemsByTestId('success-label-#password').length).toBe(1);
});
});

0 comments on commit 9933a93

Please sign in to comment.