/* xeslint-disable */ /////////////////////////////// // gzform // // provides form services and utilities // validation services // dirty and change tracking // and also general error display in forms //probably should be broken up more // All locale keys for validation *MUST* be fetched prior to this being used as it assumes all keys are fetched first // Add any new keys used to the block in locale.js=>commonKeysEditForm import Vue from "vue"; import errorHandler from "./errorhandler"; import store from "../store"; var triggeringChange = false; function isEmpty(o) { if (typeof o == "number" && o == 0) { return false; } return !o; } //////////////////////////////////// // isInt value?? // //FROM HERE: https://stackoverflow.com/a/14794066/8939 //fast test if is an integer: function isInt(value) { var x; if (isNaN(value)) { return false; } x = parseFloat(value); return (x | 0) === x; } //////////////////////////////////// // isNumber // //FROM HERE: https://stackoverflow.com/a/1830632/8939 function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } //////////////////////////////////// // Get control from ref // function getControl(vm, ref) { var ctrl = vm.$refs[ref]; return ctrl; } //////////////////////////////////// // Get value from control // function getControlValue(ctrl) { var value = ctrl.value; return value; } //////////////////////////////////// // Get field name from control // function getControlLabel(ctrl) { if (errorHandler.developmentModeShowErrorsImmediately) { if (!ctrl.label) { throw "gzform:getControlLabel - the control has no label " + ctrl; } } return ctrl.label; } ///////////////////////////////////////// // Get errors for a particular field // from server error collection // function getErrorsForField(vm, ref) { var ret = []; if (ref == "errorbox") { ret = vm.$_.filter(vm.formState.serverError.details, function(o) { return !o.target; }); } else { ret = vm.$_.filter(vm.formState.serverError.details, function(o) { if (!o.target) { return false; } //server error fields are capitalized return o.target.toLowerCase() == ref; }); } return ret; } /////////////////////////////// // ERROR BOX ERRORS // gathers any messages for error box on form which is the generic catch all for non field specific errors from server // and application itself locally function getErrorBoxErrors(vm, errs) { var hasErrors = false; var ret = ""; if (errs.length > 0) { hasErrors = true; //loop array and append each error to a return string for (var i = 0; i < errs.length; i++) { ret += errs[i] + "\r\n"; } } //any application errors? if (vm.formState.appError) { hasErrors = true; ret = vm.formState.appError + "\r\n----------\r\n" + ret; } if (!hasErrors) { return null; } else { return ret; } } export default { /////////////////////////////// // REQUIRED // required(vm, ref) { if (vm.formState.loading) { return false; } var ctrl = getControl(vm, ref); if (typeof ctrl == "undefined") { return false; } var value = getControlValue(ctrl); if (!isEmpty(value)) { return false; } // "ErrorRequiredFieldEmpty": "{0} is a required field. Please enter a value for {0}", var err = vm.$gzlocale.get("ErrorRequiredFieldEmpty"); var fieldName = getControlLabel(ctrl); err = vm.$_.replace(err, "{0}", fieldName); //lodash replace only replaces first instance so need to do it twice err = vm.$_.replace(err, "{0}", fieldName); //Update the form status this.setFormState({ vm: vm, valid: false }); return err; }, /////////////////////////////// // MAXLENGTH // maxLength(vm, ref, max) { if (vm.formState.loading) { return false; } var ctrl = getControl(vm, ref); if (typeof ctrl == "undefined") { return false; } var value = getControlValue(ctrl); if (isEmpty(value)) { return false; } if (value.length > max) { //get the localized rule text // "ErrorFieldLengthExceeded": "{0} can not exceed {1} characters.", var err = vm.$gzlocale.get("ErrorFieldLengthExceeded"); var fieldName = getControlLabel(ctrl); err = vm.$_.replace(err, "{0}", fieldName); err = vm.$_.replace(err, "{1}", max); //Update the form status this.setFormState({ vm: vm, valid: false }); return err; } else { return false; } }, /////////////////////////////// // MAX 255 // max255(vm, ref) { if (vm.formState.loading) { return false; } return this.maxLength(vm, ref, 255); }, /////////////////////////////// // DatePrecedence // (start date must precede end date) // datePrecedence(vm, refStart, refEnd) { if (vm.formState.loading) { return false; } var ctrlStart = getControl(vm, refStart); if (typeof ctrlStart == "undefined") { return false; } var ctrlEnd = getControl(vm, refEnd); if (typeof ctrlEnd == "undefined") { return false; } var valueStart = getControlValue(ctrlStart); if (isEmpty(valueStart)) { return false; } var valueEnd = getControlValue(ctrlEnd); if (isEmpty(valueEnd)) { return false; } valueStart = vm.$dayjs(valueStart); valueEnd = vm.$dayjs(valueEnd); // if either is not valid. if (!valueStart || !valueEnd) { return false; } if (valueStart.isAfter(valueEnd)) { // "ErrorStartDateAfterEndDate": "Start date must be earlier than stop / end date", var err = vm.$gzlocale.get("ErrorStartDateAfterEndDate"); //Update the form status this.setFormState({ vm: vm, valid: false }); return err; } else { return false; } }, /////////////////////////////// // INTEGER IS VALID // integerValid(vm, ref) { if (vm.formState.loading) { return false; } var ctrl = getControl(vm, ref); if (typeof ctrl == "undefined") { return false; } //DEBUG //logControl("integerValid", ctrl, ref); var value = getControlValue(ctrl); if (isEmpty(value)) { return false; } if (isInt(value)) { return false; } // "ErrorFieldValueNotInteger": "Value must be an integer" var err = vm.$gzlocale.get("ErrorFieldValueNotInteger"); //Update the form status this.setFormState({ vm: vm, valid: false }); return err; }, /////////////////////////////// // DECIMAL // Basically anything that can be a number is valid // decimalValid(vm, ref) { if (vm.formState.loading) { return false; } //TODO: Handle commas and spaces in numbers //as per vm.$gzlocale rules for numbers var ctrl = getControl(vm, ref); if (typeof ctrl == "undefined") { return false; } //DEBUG //logControl("decimalValid", ctrl, ref); var value = getControlValue(ctrl); if (isEmpty(value)) { return false; } if (isNumber(value)) { return false; } // "ErrorFieldValueNotDecimal": "Value must be a number" var err = vm.$gzlocale.get("ErrorFieldValueNotDecimal"); //Update the form status this.setFormState({ vm: vm, valid: false }); return err; }, /////////////////////////////// // SERVER ERRORS // Process and return server errors if any for form and field specified // serverErrors(vm, ref) { //CHECK PREREQUISITES IN DEV MODE TO ENSURE FORM ISN"T MISSING NEEDED DATA ATTRIBUTES ETC if (vm.$gzdevmode()) { //make sure formState.serverErrors is defined on data if (!vm.$_.has(vm, "formState.serverError")) { throw "DEV ERROR gzform::formState.serverErrors -> formState.serverError seems to be missing from form's vue data object"; } //make sure formState.appError is defined on data if (!vm.$_.has(vm, "formState.appError")) { throw "DEV ERROR gzform::formState.serverErrors -> formState.appError seems to be missing from form's vue data object"; } //make sure formState.errorBoxMessage is defined on data if (!vm.$_.has(vm, "formState.errorBoxMessage")) { throw "DEV ERROR gzform::formState.serverErrors -> formState.errorBoxMessage seems to be missing from form's vue data object"; } //ensure the error returned is in an expected format to catch coding errors at the server end if (!vm.$_.isEmpty(vm.formState.serverError)) { //Make sure there is an error code if there is an error collection if (!vm.formState.serverError.code) { throw "DEV ERROR gzform::formState.serverErrors -> server returned error without code"; } } } var ret = []; //check for errors if we have any errors if (!vm.$_.isEmpty(vm.formState.serverError)) { //debugger; //First let's get the top level error code var apiErrorCode = parseInt(vm.formState.serverError.code); //GENERAL ERROR if (ref == "errorbox") { //Add any general errors to ret var err = vm.$gzlocale.get("ErrorAPI" + apiErrorCode.toString()); if (vm.formState.serverError.message) { err = err + "\r\n" + vm.formState.serverError.message; } //Update the form status this.setFormState({ vm: vm, valid: false }); ret.push(err); } //DETAIL ERRORS //{"error":{"code":"2200","details":[{"message":"Exception: Error converting value \"\" to type 'AyaNova.Biz.AUTHORIZATION_ROLES'. Path 'roles', line 1, position 141.","target":"roles","error":"2203"}],"message":"Object did not pass validation"}} //Specific field validation errors are in an array in "details" key if (!vm.$_.isEmpty(vm.formState.serverError.details)) { //See if this key is in the details array var errorsForField = getErrorsForField(vm, ref); if (errorsForField.length > 0) { //iterate the errorsForField object and add each to return array of errors vm.$_.each(errorsForField, function(ve) { var fldErr = ""; var fldErrorCode = parseInt(ve.error); fldErr = vm.$gzlocale.get("ErrorAPI" + fldErrorCode.toString()) + " [" + ve.error + "]"; if (ve.message) { fldErr += ' - "' + ve.message + '"'; } ret.push(fldErr); }); //Update the form status this.setFormState({ vm: vm, valid: false }); return ret; } } } //default if no error message to display return ret; }, /////////////////////////////// // ClearformState.serverErrors // Clear all server errors and app errors and ensure error box doesn't show // deleteAllErrorBoxErrors(vm) { //clear all keys from server error vm.$gzutil.removeAllPropertiesFromObject(vm.formState.serverError); //clear app errors vm.formState.appError = null; //clear out actual message box display vm.formState.errorBoxMessage = null; //Update the form status this.setFormState({ vm: vm, valid: true }); }, /////////////////////////////// // setErrorBoxErrors // Gather server errors and set the appropriate keys // setErrorBoxErrors(vm) { var errs = this.serverErrors(vm, "errorbox"); var ret = getErrorBoxErrors(vm, errs); vm.formState.errorBoxMessage = ret; }, /////////////////////////////// // On onChange handler // This is required so that server errors can be cleared when input is changed // onChange(vm, ref) { //xeslint-disable-next-line //console.log("GZFORM::onChange triggered!"); if (triggeringChange || vm.formState.loading) { return; } //If ref appears in the formState.serverErrors details collection, remove each one var m = vm.$_.remove(vm.formState.serverError.details, function(o) { if (!o.target) { return false; } return o.target.toLowerCase() == ref; }); //If there are no more errors in details then remove the whole thing as it's no longer required if ( vm.formState.serverError.details && vm.formState.serverError.details.length < 1 ) { if (vm.formState.serverError.code == "2200") { //clear all keys from server error vm.$gzutil.removeAllPropertiesFromObject(vm.formState.serverError); } } //Clear out old validation display in form by forcing the control's data to change //I tried calling form validate and reset and all that bullshit but it did nothing //probably because it has safeguards to prevent excess validation, this works though so far //I added the triggering change guard but it actually doesn't seem to be required here, more investigation is required if (m.length > 0) { triggeringChange = true; var val = vm.obj[ref]; vm.obj[ref] = null; vm.obj[ref] = val; triggeringChange = false; } //Update the form status this.setFormState({ vm: vm, dirty: true, valid: vm.$refs.form.validate() }); }, //////////////////////////////////// // set calling form Valid state // // {vm:vm,dirty:bool | undefined, // valid:bool | undefined, // loading:bool | undefined} // setFormState(newState) { //this returns a promise so any function that needs to wait for this can utilize that return Vue.nextTick(function() { if (newState.valid != undefined) { newState.vm.formState.valid = newState.valid; } if (newState.dirty != undefined) { newState.vm.formState.dirty = newState.dirty; } if (newState.loading != undefined) { newState.vm.formState.loading = newState.loading; } if (newState.readOnly != undefined) { newState.vm.formState.readOnly = newState.readOnly; } }); }, //////////////////////////////////// // Get form settings // for form specified or empty object if there is none // EAch form is responsible for what it stores and how it initializes, this just provides that // the form does the actual work of what settings it requires // getFormSettings(formKey) { var theFormSettings = store.state.formSettings[formKey]; return theFormSettings; }, //////////////////////////////////// // Set form settings // for form key specified // // setFormSettings(formKey, formSettings) { store.commit("setFormSettings", formKey, formSettings); } };