Form.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { useState } from 'react';
  2. import { checkEmptyValid, getCheckResult } from '../utils/Validation';
  3. import type { IValidation } from '../components/customInput/Types';
  4. export interface IForm {
  5. key: string;
  6. value?: any;
  7. needCheck?: boolean;
  8. }
  9. interface IValidationInfo {
  10. // check general validation
  11. checkFormValid: Function;
  12. // check detail validation
  13. checkIsValid: Function;
  14. validation: {
  15. [key: string]: IValidationItem;
  16. };
  17. disabled: boolean;
  18. setDisabled: Function;
  19. resetValidation: (form: IForm[]) => void;
  20. }
  21. export interface IValidationItem {
  22. result: boolean;
  23. errText: string;
  24. }
  25. export interface ICheckValidParam {
  26. value: string;
  27. key: string;
  28. // one input can contains multiple rules
  29. rules: IValidation[];
  30. }
  31. // form and element ref
  32. export const useFormValidation = (form: IForm[]): IValidationInfo => {
  33. const initValidation = form
  34. .filter(f => f.needCheck)
  35. .reduce(
  36. (acc, cur) => ({
  37. ...acc,
  38. [cur.key]: {
  39. result:
  40. typeof cur.value === 'string' ? cur.value === '' : cur.value === 0,
  41. errText: '',
  42. },
  43. }),
  44. {}
  45. );
  46. // validation detail about form item
  47. const [validation, setValidation] = useState(initValidation);
  48. // overall validation result to control following actions
  49. const isOverallValid = Object.values(validation).every(
  50. v => !(v as IValidationItem).result
  51. );
  52. const [disabled, setDisabled] = useState<boolean>(!isOverallValid);
  53. const checkIsValid = (param: ICheckValidParam): IValidationItem => {
  54. const { value, key, rules } = param;
  55. let validDetail = {
  56. result: false,
  57. errText: '',
  58. };
  59. const hasRequire = rules.some(r => r.rule === 'require');
  60. // if value is empty, and no require rule, skip this check
  61. if (!checkEmptyValid(value) && !hasRequire) {
  62. setDisabled(false);
  63. return validDetail;
  64. }
  65. for (let i = 0; i < rules.length; i++) {
  66. const rule = rules[i];
  67. const checkResult = getCheckResult({
  68. value,
  69. extraParam: rule.extraParam,
  70. rule: rule.rule,
  71. });
  72. if (!checkResult) {
  73. validDetail = {
  74. result: true,
  75. errText: rule.errorText || '',
  76. };
  77. break;
  78. }
  79. }
  80. const validInfo = {
  81. ...validation,
  82. [key]: validDetail,
  83. };
  84. const isOverallValid = Object.values(validInfo).every(
  85. v => !(v as IValidationItem).result
  86. );
  87. setDisabled(!isOverallValid);
  88. setValidation(validInfo);
  89. return validDetail;
  90. };
  91. const checkFormValid = (elementClass: string) => {
  92. // find dom element to check
  93. const elements = document.querySelectorAll(
  94. elementClass
  95. ) as NodeListOf<HTMLElement>;
  96. // Trigger blur
  97. elements.forEach(element => {
  98. // Using setTimeout to trigger blur event after render
  99. setTimeout(() => {
  100. // Using HTMLElement.prototype.blur method to trigger blur event
  101. element.focus();
  102. element.blur();
  103. }, 0);
  104. });
  105. };
  106. const resetValidation = (form: IForm[]) => {
  107. const validation = form
  108. .filter(f => f.needCheck)
  109. .reduce(
  110. (acc, cur) => ({
  111. ...acc,
  112. [cur.key]: { result: cur.value === '', errText: '' },
  113. }),
  114. {}
  115. );
  116. setValidation(validation);
  117. };
  118. return {
  119. checkFormValid,
  120. checkIsValid,
  121. validation,
  122. disabled,
  123. setDisabled,
  124. resetValidation,
  125. };
  126. };