useForm.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = void 0;
  7. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  10. var _vue = require("vue");
  11. var _cloneDeep = _interopRequireDefault(require("lodash/cloneDeep"));
  12. var _intersection = _interopRequireDefault(require("lodash/intersection"));
  13. var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
  14. var _debounce = _interopRequireDefault(require("lodash/debounce"));
  15. var _omit = _interopRequireDefault(require("lodash/omit"));
  16. var _validateUtil = require("./utils/validateUtil");
  17. var _messages = require("./utils/messages");
  18. var _asyncUtil = require("./utils/asyncUtil");
  19. function isRequired(rules) {
  20. var isRequired = false;
  21. if (rules && rules.length) {
  22. rules.every(function (rule) {
  23. if (rule.required) {
  24. isRequired = true;
  25. return false;
  26. }
  27. return true;
  28. });
  29. }
  30. return isRequired;
  31. }
  32. function toArray(value) {
  33. if (value === undefined || value === null) {
  34. return [];
  35. }
  36. return Array.isArray(value) ? value : [value];
  37. }
  38. function getPropByPath(obj, path, strict) {
  39. var tempObj = obj;
  40. path = path.replace(/\[(\w+)\]/g, '.$1');
  41. path = path.replace(/^\./, '');
  42. var keyArr = path.split('.');
  43. var i = 0;
  44. for (var len = keyArr.length; i < len - 1; ++i) {
  45. if (!tempObj && !strict) break;
  46. var key = keyArr[i];
  47. if (key in tempObj) {
  48. tempObj = tempObj[key];
  49. } else {
  50. if (strict) {
  51. throw new Error('please transfer a valid name path to validate!');
  52. }
  53. break;
  54. }
  55. }
  56. return {
  57. o: tempObj,
  58. k: keyArr[i],
  59. v: tempObj ? tempObj[keyArr[i]] : null,
  60. isValid: tempObj && keyArr[i] in tempObj
  61. };
  62. }
  63. function useForm(modelRef) {
  64. var rulesRef = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : (0, _vue.ref)({});
  65. var options = arguments.length > 2 ? arguments[2] : undefined;
  66. var initialModel = (0, _cloneDeep.default)((0, _vue.unref)(modelRef));
  67. var validateInfos = (0, _vue.reactive)({});
  68. var rulesKeys = (0, _vue.shallowRef)([]);
  69. var resetFields = function resetFields(newValues) {
  70. (0, _extends2.default)((0, _vue.unref)(modelRef), (0, _objectSpread2.default)((0, _objectSpread2.default)({}, (0, _cloneDeep.default)(initialModel)), newValues));
  71. (0, _vue.nextTick)(function () {
  72. Object.keys(validateInfos).forEach(function (key) {
  73. validateInfos[key] = {
  74. autoLink: false,
  75. required: isRequired((0, _vue.unref)(rulesRef)[key])
  76. };
  77. });
  78. });
  79. };
  80. var filterRules = function filterRules() {
  81. var rules = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  82. var trigger = arguments.length > 1 ? arguments[1] : undefined;
  83. if (!trigger.length) {
  84. return rules;
  85. } else {
  86. return rules.filter(function (rule) {
  87. var triggerList = toArray(rule.trigger || 'change');
  88. return (0, _intersection.default)(triggerList, trigger).length;
  89. });
  90. }
  91. };
  92. var lastValidatePromise = null;
  93. var validateFields = function validateFields(names) {
  94. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  95. var strict = arguments.length > 2 ? arguments[2] : undefined;
  96. // Collect result in promise list
  97. var promiseList = [];
  98. var values = {};
  99. var _loop = function _loop(i) {
  100. var name = names[i];
  101. var prop = getPropByPath((0, _vue.unref)(modelRef), name, strict);
  102. if (!prop.isValid) return "continue";
  103. values[name] = prop.v;
  104. var rules = filterRules((0, _vue.unref)(rulesRef)[name], toArray(option && option.trigger));
  105. if (rules.length) {
  106. promiseList.push(validateField(name, prop.v, rules, option || {}).then(function () {
  107. return {
  108. name: name,
  109. errors: [],
  110. warnings: []
  111. };
  112. }).catch(function (ruleErrors) {
  113. var mergedErrors = [];
  114. var mergedWarnings = [];
  115. ruleErrors.forEach(function (_ref) {
  116. var warningOnly = _ref.rule.warningOnly,
  117. errors = _ref.errors;
  118. if (warningOnly) {
  119. mergedWarnings.push.apply(mergedWarnings, (0, _toConsumableArray2.default)(errors));
  120. } else {
  121. mergedErrors.push.apply(mergedErrors, (0, _toConsumableArray2.default)(errors));
  122. }
  123. });
  124. if (mergedErrors.length) {
  125. return Promise.reject({
  126. name: name,
  127. errors: mergedErrors,
  128. warnings: mergedWarnings
  129. });
  130. }
  131. return {
  132. name: name,
  133. errors: mergedErrors,
  134. warnings: mergedWarnings
  135. };
  136. }));
  137. }
  138. };
  139. for (var i = 0; i < names.length; i++) {
  140. var _ret = _loop(i);
  141. if (_ret === "continue") continue;
  142. }
  143. var summaryPromise = (0, _asyncUtil.allPromiseFinish)(promiseList);
  144. lastValidatePromise = summaryPromise;
  145. var returnPromise = summaryPromise.then(function () {
  146. if (lastValidatePromise === summaryPromise) {
  147. return Promise.resolve(values);
  148. }
  149. return Promise.reject([]);
  150. }).catch(function (results) {
  151. var errorList = results.filter(function (result) {
  152. return result && result.errors.length;
  153. });
  154. return Promise.reject({
  155. values: values,
  156. errorFields: errorList,
  157. outOfDate: lastValidatePromise !== summaryPromise
  158. });
  159. });
  160. // Do not throw in console
  161. returnPromise.catch(function (e) {
  162. return e;
  163. });
  164. return returnPromise;
  165. };
  166. var validateField = function validateField(name, value, rules) {
  167. var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  168. var promise = (0, _validateUtil.validateRules)([name], value, rules, (0, _objectSpread2.default)({
  169. validateMessages: _messages.defaultValidateMessages
  170. }, option), !!option.validateFirst);
  171. if (!validateInfos[name]) {
  172. return promise.catch(function (e) {
  173. return e;
  174. });
  175. }
  176. validateInfos[name].validateStatus = 'validating';
  177. promise.catch(function (e) {
  178. return e;
  179. }).then(function () {
  180. var results = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  181. if (validateInfos[name].validateStatus === 'validating') {
  182. var _options$onValidate;
  183. var res = results.filter(function (result) {
  184. return result && result.errors.length;
  185. });
  186. validateInfos[name].validateStatus = res.length ? 'error' : 'success';
  187. validateInfos[name].help = res.length ? res.map(function (r) {
  188. return r.errors;
  189. }) : null;
  190. options === null || options === void 0 ? void 0 : (_options$onValidate = options.onValidate) === null || _options$onValidate === void 0 ? void 0 : _options$onValidate.call(options, name, !res.length, res.length ? (0, _vue.toRaw)(validateInfos[name].help[0]) : null);
  191. }
  192. });
  193. return promise;
  194. };
  195. var validate = function validate(names, option) {
  196. var keys = [];
  197. var strict = true;
  198. if (!names) {
  199. strict = false;
  200. keys = rulesKeys.value;
  201. } else if (Array.isArray(names)) {
  202. keys = names;
  203. } else {
  204. keys = [names];
  205. }
  206. var promises = validateFields(keys, option || {}, strict);
  207. // Do not throw in console
  208. promises.catch(function (e) {
  209. return e;
  210. });
  211. return promises;
  212. };
  213. var clearValidate = function clearValidate(names) {
  214. var keys = [];
  215. if (!names) {
  216. keys = rulesKeys.value;
  217. } else if (Array.isArray(names)) {
  218. keys = names;
  219. } else {
  220. keys = [names];
  221. }
  222. keys.forEach(function (key) {
  223. validateInfos[key] && (0, _extends2.default)(validateInfos[key], {
  224. validateStatus: '',
  225. help: null
  226. });
  227. });
  228. };
  229. var mergeValidateInfo = function mergeValidateInfo(items) {
  230. var info = {
  231. autoLink: false
  232. };
  233. var help = [];
  234. var infos = Array.isArray(items) ? items : [items];
  235. for (var i = 0; i < infos.length; i++) {
  236. var arg = infos[i];
  237. if ((arg === null || arg === void 0 ? void 0 : arg.validateStatus) === 'error') {
  238. info.validateStatus = 'error';
  239. arg.help && help.push(arg.help);
  240. }
  241. info.required = info.required || (arg === null || arg === void 0 ? void 0 : arg.required);
  242. }
  243. info.help = help;
  244. return info;
  245. };
  246. var oldModel = initialModel;
  247. var isFirstTime = true;
  248. var modelFn = function modelFn(model) {
  249. var names = [];
  250. rulesKeys.value.forEach(function (key) {
  251. var prop = getPropByPath(model, key, false);
  252. var oldProp = getPropByPath(oldModel, key, false);
  253. var isFirstValidation = isFirstTime && (options === null || options === void 0 ? void 0 : options.immediate) && prop.isValid;
  254. if (isFirstValidation || !(0, _isEqual.default)(prop.v, oldProp.v)) {
  255. names.push(key);
  256. }
  257. });
  258. validate(names, {
  259. trigger: 'change'
  260. });
  261. isFirstTime = false;
  262. oldModel = (0, _cloneDeep.default)((0, _vue.toRaw)(model));
  263. };
  264. var debounceOptions = options === null || options === void 0 ? void 0 : options.debounce;
  265. var first = true;
  266. (0, _vue.watch)(rulesRef, function () {
  267. rulesKeys.value = rulesRef ? Object.keys((0, _vue.unref)(rulesRef)) : [];
  268. if (!first && options && options.validateOnRuleChange) {
  269. validate();
  270. }
  271. first = false;
  272. }, {
  273. deep: true,
  274. immediate: true
  275. });
  276. (0, _vue.watch)(rulesKeys, function () {
  277. var newValidateInfos = {};
  278. rulesKeys.value.forEach(function (key) {
  279. newValidateInfos[key] = (0, _extends2.default)({}, validateInfos[key], {
  280. autoLink: false,
  281. required: isRequired((0, _vue.unref)(rulesRef)[key])
  282. });
  283. delete validateInfos[key];
  284. });
  285. for (var key in validateInfos) {
  286. if (Object.prototype.hasOwnProperty.call(validateInfos, key)) {
  287. delete validateInfos[key];
  288. }
  289. }
  290. (0, _extends2.default)(validateInfos, newValidateInfos);
  291. }, {
  292. immediate: true
  293. });
  294. (0, _vue.watch)(modelRef, debounceOptions && debounceOptions.wait ? (0, _debounce.default)(modelFn, debounceOptions.wait, (0, _omit.default)(debounceOptions, ['wait'])) : modelFn, {
  295. immediate: options && !!options.immediate,
  296. deep: true
  297. });
  298. return {
  299. modelRef: modelRef,
  300. rulesRef: rulesRef,
  301. initialModel: initialModel,
  302. validateInfos: validateInfos,
  303. resetFields: resetFields,
  304. validate: validate,
  305. validateField: validateField,
  306. mergeValidateInfo: mergeValidateInfo,
  307. clearValidate: clearValidate
  308. };
  309. }
  310. var _default = useForm;
  311. exports.default = _default;