Skip to content

Commit 398b8b5

Browse files
committed
Add MinimumFieldValuesFieldsetValidationElement; tests
* Implementation example of `FieldsetValidationElement`, while also addressing a 101-level validation problem
1 parent a1ce01a commit 398b8b5

File tree

6 files changed

+388
-40
lines changed

6 files changed

+388
-40
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"./utils": "./src/util.js",
1616
"./fieldset/rendering": "./src/fieldset/rendering.js",
1717
"./fieldset/fieldset-validation-element": "./src/fieldset/fieldset-validation-element.js",
18+
"./fieldset/minimum-field-values-fieldset-validation-element": "./src/fieldset/minimum-field-values-fieldset-validation-element.js",
1819
"./fieldset/util": "./src/fieldset/util.js"
1920
},
2021
"scripts": {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { FieldsetValidationElement } from './fieldset-validation-element.js'
2+
3+
import {
4+
skipFieldsetChangeEvent,
5+
skipFieldsetFocusoutEvent
6+
} from './util.js'
7+
8+
import {
9+
clearErrorListForFieldset,
10+
renderCustomErrorMessageForFieldset
11+
} from './rendering.js'
12+
13+
/**
14+
* Checks that there is at least N values in the `FormData` for the given
15+
* `fieldName` in the `fieldset`'s form.
16+
* @param {FieldsetElement} fieldset
17+
* @param {string} fieldName
18+
* @param {integer} minimum
19+
* @return {boolean} if there is at least 1 record for `fieldName` in the fieldset form's `FormData`
20+
*/
21+
export function minimumCountOfFieldNameSelected(fieldset, fieldName, minimum) {
22+
const formData = new FormData(fieldset.form)
23+
return formData.getAll(fieldName).length >= minimum
24+
}
25+
26+
27+
/**
28+
* Calls {@link MinimumFieldValuesFieldsetValidationElement#reportValidity} unless
29+
* {@link skipFieldsetChangeEvent} returns `true`
30+
*/
31+
export function changeValidationEventHandler(event) {
32+
if(skipFieldsetChangeEvent(event)){ return }
33+
const element = event.currentTarget
34+
element.reportValidity()
35+
}
36+
37+
/**
38+
* Calls {@link MinimumFieldValuesFieldsetValidationElement#reportValidity} unless
39+
* {@link focusoutValidationEventHandler} returns `true`
40+
*/
41+
export function focusoutValidationEventHandler(event) {
42+
if(skipFieldsetFocusoutEvent(event)){ return }
43+
const element = event.currentTarget
44+
element.reportValidity()
45+
}
46+
47+
/**
48+
* @class
49+
* @classdesc
50+
* @extends FieldsetValidationElement
51+
* A custom element that can validate that a minimum number of values for the given `field-name`
52+
* Match `
53+
*/
54+
export class MinimumFieldValuesFieldsetValidationElement extends FieldsetValidationElement {
55+
/**
56+
* Returns the value of the `min`, parsed as an Integer
57+
*/
58+
get min() {
59+
return Number.parseInt(this.getAttribute(`min`))
60+
}
61+
62+
/**
63+
* Returns the value of the `validation-message`, throwing a `TypeError`` if it is missing
64+
*/
65+
get validationMessage() {
66+
const message = this.getAttribute(`validation-message`)
67+
if(!message || message.trim() === ""){ throw new TypeError(`validation-message missing`) }
68+
69+
return message
70+
}
71+
72+
/**
73+
* Returns the value of the `validation-message`, throwing a `TypeError`` if it is missing
74+
*/
75+
get type() {
76+
const type = this.getAttribute(`type`)
77+
if(!type || type.trim() === ""){ throw new TypeError(`type missing`) }
78+
79+
return type
80+
}
81+
82+
/**
83+
* Calls:
84+
* - {@link clearErrorListForFieldset}
85+
* - {@link minimumCountOfFieldNameSelected}
86+
* - {@link renderCustomErrorMessageForFieldset}
87+
*/
88+
reportValidity() {
89+
clearErrorListForFieldset(this.fieldset)
90+
91+
if(minimumCountOfFieldNameSelected(this.fieldset, this.fieldName, this.min)) {
92+
return true
93+
}
94+
95+
renderCustomErrorMessageForFieldset(this.fieldset, this.validationMessage, this.type)
96+
97+
return false
98+
}
99+
100+
connectedCallback() {
101+
super.connectedCallback()
102+
this.addEventListeners()
103+
}
104+
105+
addEventListeners() {
106+
this.addEventListener(`change`, changeValidationEventHandler)
107+
this.addEventListener(`focusout`, focusoutValidationEventHandler)
108+
109+
const element = this
110+
const submitValidationEventHandler = function (event) {
111+
const isValid = element.reportValidity()
112+
113+
if(!isValid) {
114+
event.preventDefault()
115+
element.fieldset.querySelector(`input:first-child`).focus()
116+
}
117+
}
118+
119+
this.form.addEventListener(`submit`, submitValidationEventHandler)
120+
}
121+
}
122+
123+
if (!window.customElements.get('minimum-field-values-fieldset-validation')) {
124+
window.customElements.define(
125+
'minimum-field-values-fieldset-validation',
126+
MinimumFieldValuesFieldsetValidationElement)
127+
;
128+
}

src/fieldset/util.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,6 @@ import {
44
skipValidation
55
} from "../element-utilities.js"
66

7-
/**
8-
* Checks that there is at least N values in the `FormData` for the given
9-
* `fieldName` in the `fieldset`'s form.
10-
* @param {FieldsetElement} fieldset
11-
* @param {string} fieldName
12-
* @param {integer} minimum
13-
* @return {boolean} if there is at least 1 record for `fieldName` in the fieldset form's `FormData`
14-
*/
15-
export function minimumCountOfFieldNameSelected(fieldset, fieldName, minimum) {
16-
const formData = new FormData(fieldset.form)
17-
return formData.getAll(fieldName).length >= minimum
18-
}
19-
207
/**
218
* Helper method to check if the the `ChangeEvent` is inside of
229
* its target.

0 commit comments

Comments
 (0)