export class VErrors { constructor(event) { this.event = event; } clearErrors() { var errorMessages = document.querySelectorAll('.v-error-message'); for (var i = 0; i < errorMessages.length; i++) { errorMessages[i].remove(); } } // Rails errors // { // "name": [ // "Requires name" // ] // } // Validation errors // { :email => ["must be filled"] } // Custom errors // { :email => "must be filled" } // Exceptions // {exception: 'Something bad happened' } stringsToArrays(value) { if (Array.isArray(value) || value.constructor === Object) { return value; } return new Array(value); } normalizeErrors(errors) { if (errors && errors.constructor === Object) { return Object.keys(errors).reduce((previous, key) => { previous[key] = this.stringsToArrays(errors[key]); return previous; }, {}); } return []; } // [http_status, content_type, resultText] displayErrors(result) { var httpStatus = result.statusCode; var contentType = result.contentType; var resultText = result.content; var responseErrors = null; if (contentType && contentType.indexOf("application/json") !== -1) { responseErrors = JSON.parse(resultText); } else if (contentType && contentType.indexOf("v/errors") !== -1) { responseErrors = resultText; } if (responseErrors) { if (!Array.isArray(responseErrors)) { responseErrors = [responseErrors]; } for (var response of responseErrors) { var pageErrors = Object.values(this.normalizeErrors(response)).reduce(function (previous, value) { if (Array.isArray(value)) { previous.push(value.join('
')); } return previous; }, []); var fieldErrors = this.normalizeErrors(response.errors); for (var field in fieldErrors) { if (!this.displayInputError(field, fieldErrors[field])) { // Collect errors that can't be displayed at the field level pageErrors.push(fieldErrors[field]); } } this.prependErrors(pageErrors); } } else if (httpStatus === 0) { this.prependErrors(["Unable to contact server. Please check that you are online and retry."]); } else { this.prependErrors(["The server returned an unexpected response! Status:" + httpStatus]); } } // Sets the helper text on the field // Returns true if it was able to set the error on the control displayInputError(divId, messages) { var currentEl = document.getElementById(divId); if (currentEl && currentEl.mdcComponent) { currentEl.mdcComponent.helperTextContent = messages.join(', '); var helperText = document.getElementById(divId + '-input-helper-text'); helperText.classList.add('mdc-text-field--invalid', 'mdc-text-field-helper-text--validation-msg', 'mdc-text-field-helper-text--persistent'); currentEl.mdcComponent.valid = false; return true; } return false; } // Creates a div before the element with the same id as the error // Used to display an error message without their being an input field to attach the error to prependErrors(messages) { var errorsDiv = this.findNearestErrorDiv(); // create a new div element var newDiv = document.createElement("div"); newDiv.className = 'v-error-message'; // and give it some content for (var message of messages) { var newContent = document.createTextNode(message); newDiv.appendChild(newContent); let br = document.createElement('br'); // add the text node to the newly created div newDiv.appendChild(br); } // add the newly created element and its content into the DOM if (errorsDiv) { errorsDiv.parentElement.insertBefore(newDiv, errorsDiv); return true; } else { console.error("Unable to display Errors! ", messages); } return false; } findNearestErrorDiv() { let errorsDiv = null; const currentDiv = this.event.target; if(currentDiv) { errorsDiv = currentDiv.closest('.v-errors') }else{ errorsDiv = document.querySelector('.v-errors'); } return errorsDiv; } }