@ministryofjustice/hmpps-digital-prison-reporting-frontend
Version:
The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.
136 lines (120 loc) • 4.76 kB
JavaScript
/* eslint-disable class-methods-use-this */
import DprQueryParamClass from './DprQueryParamClass.mjs'
export default class DprFormValidationClass extends DprQueryParamClass {
initFormValidation(formFields) {
formFields.forEach((field) => {
const formGroup = field.closest('div.govuk-form-group')
if (formGroup) {
const errorMessageEl = formGroup.querySelector('p.govuk-error-message')
if (errorMessageEl) {
formGroup.classList.remove('govuk-form-group--error')
errorMessageEl.classList.add('govuk-error-message--hidden')
field.classList.remove('govuk-input--error')
field.classList.remove('govuk-textarea--error')
field.classList.remove('govuk-select--error')
}
}
})
}
validateForm() {
this.errorMessages = []
let prevfieldName = ''
this.formFields.forEach((field) => {
const currentFieldName = field.getAttribute('name')
if (currentFieldName !== prevfieldName && field.tagName !== 'BUTTON') {
const formGroupEl = field.closest('div.govuk-form-group')
if (formGroupEl) {
const errorMessageEl = formGroupEl.querySelector('p.govuk-error-message')
if (!this.fieldIsValid(field)) {
this.showFieldError(field, formGroupEl, errorMessageEl)
} else if (errorMessageEl && formGroupEl) {
this.hideFieldError(field, formGroupEl, errorMessageEl)
}
}
}
prevfieldName = field.getAttribute('name')
})
if (this.errorMessages.length) {
this.buildErrorSummary()
this.errorSummary.classList.remove('query-error-summary--hidden')
} else {
this.errorSummary.classList.add('query-error-summary--hidden')
}
}
fieldIsValid(field) {
const { type } = field
switch (type) {
case 'checkbox':
return this.validateCheckbox(field)
default:
return field.checkValidity()
}
}
validateCheckbox(field) {
const checkboxWrapper = field.closest('div.govuk-checkboxes')
if (checkboxWrapper.hasAttribute('required')) {
const checkboxes = checkboxWrapper.querySelectorAll('input[type="checkbox"]')
return Array.from(checkboxes).some((x) => x.checked)
}
return true
}
showFieldError(field, formGroupEl, errorMessageEl) {
formGroupEl.classList.add('govuk-form-group--error')
const message = this.setValidationMessage(field.validity, field, errorMessageEl)
// eslint-disable-next-line no-param-reassign
errorMessageEl.innerHTML = `<span class="govuk-visually-hidden">Error:</span>${message}`
errorMessageEl.classList.remove('govuk-error-message--hidden')
field.classList.add('govuk-input--error')
}
hideFieldError(field, formGroupEl, errorMessageEl) {
formGroupEl.classList.remove('govuk-form-group--error')
errorMessageEl.classList.add('govuk-error-message--hidden')
field.classList.remove('govuk-input--error')
}
buildErrorSummary() {
const errorSummaryBody = this.errorSummary.querySelector('div.govuk-error-summary__body')
let messages = ''
this.errorMessages.forEach((m) => {
messages += `<li><a href="${m.href}">${m.text}</a></li>`
})
const errorMessages = `<ul class="govuk-list govuk-error-summary__list">${messages}</ul>`
errorSummaryBody.innerHTML = errorMessages
}
getDisplayName(field) {
const type = field.getAttribute('type')
switch (type) {
case 'text':
return field.getAttribute('display-name')
case 'radio':
return field.closest('div.govuk-radios').getAttribute('display-name')
case 'checkbox':
return field.closest('div.govuk-checkboxes').getAttribute('display-name')
default:
return field.getAttribute('display-name')
}
}
setValidationMessage(validityState, field, errorMessageEl) {
const existingErrorMessage = errorMessageEl.lastChild.nodeValue.replace(/(\r\n|\n|\r)/gm, '').trim()
const inputId = field.getAttribute('id')
const displayName = this.getDisplayName(field)
let message
if (validityState.valueMissing || field.type === 'checkbox') {
message = existingErrorMessage.length ? existingErrorMessage : `${displayName} is required`
this.errorMessages.push({
text: message,
href: `#${inputId}`,
})
}
if (validityState.patternMismatch) {
const pattern = field.getAttribute('pattern-hint') || field.getAttribute('pattern')
message = existingErrorMessage.length
? existingErrorMessage
: `The value for ${displayName} must be in the correct pattern: ${pattern}`
this.errorMessages.push({
text: message,
href: `#${inputId}`,
})
}
return message
}
}