form.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. import { __assign, __awaiter, __extends, __generator } from "tslib";
  2. import AsyncValidator from 'async-validator';
  3. var EventEmitter = /** @class */ (function () {
  4. function EventEmitter() {
  5. this.listenders = {};
  6. }
  7. EventEmitter.prototype.on = function (event, listener) {
  8. this.listenders[event] = this.listenders[event] || [];
  9. this.listenders[event].push(listener);
  10. return this;
  11. };
  12. EventEmitter.prototype.emit = function (event) {
  13. var args = [];
  14. for (var _i = 1; _i < arguments.length; _i++) {
  15. args[_i - 1] = arguments[_i];
  16. }
  17. var arr = this.listenders[event];
  18. if (arr) {
  19. arr.forEach(function (listener) { return listener.apply(void 0, args); });
  20. }
  21. };
  22. return EventEmitter;
  23. }());
  24. var Field = /** @class */ (function (_super) {
  25. __extends(Field, _super);
  26. /**
  27. * Field构建
  28. * @param ref field ref对象
  29. * @param initialValue 初始值
  30. */
  31. function Field(ref, name, initialValues, rules, validateMessages, required, label, message, validateTrigger) {
  32. var _this = _super.call(this) || this;
  33. _this.ref = ref;
  34. _this.formRules = rules;
  35. _this.create(name, initialValues[name], rules[name], validateMessages, required, label, message, validateTrigger);
  36. _this.ref.on(function (trigger, value, extraInfo) {
  37. if (trigger === 'onChange') {
  38. _this.setValue(value);
  39. _this.touched = true;
  40. _this.emit('valueChange', value);
  41. }
  42. else if (trigger === 'didUnmount') {
  43. _this.emit('didUnmount');
  44. }
  45. else if (trigger === 'deriveDataFromProps') {
  46. var props = extraInfo ? extraInfo : _this.ref.getProps();
  47. if ((value.name && value.name !== props.name) ||
  48. value.required !== props.required ||
  49. value.label !== props.label ||
  50. value.message !== props.message ||
  51. value.validateTrigger !== props.validateTrigger) {
  52. _this.create(value.name, initialValues[value.name], _this.formRules[value.name], validateMessages, value.required, value.message, value.label, value.validateTrigger, true);
  53. }
  54. if (value.name !== props.name) {
  55. _this.emit('replaceName', value.name);
  56. }
  57. }
  58. _this.validateTrigger.forEach(function (item) {
  59. if (item === trigger) {
  60. _this.validate();
  61. }
  62. });
  63. });
  64. return _this;
  65. }
  66. Field.prototype.create = function (name, initialValue, rule, validateMessages, required, label, message, validateTrigger, update) {
  67. this.name = name;
  68. this.required = this.transformValidatorRules(name, rule, required, label, message, validateMessages);
  69. if (!update) {
  70. this.reset(initialValue);
  71. }
  72. else {
  73. this.ref.setFormData({
  74. required: this.required,
  75. });
  76. }
  77. var validateTriggerList = validateTrigger || 'onChange';
  78. if (!Array.isArray(validateTriggerList)) {
  79. validateTriggerList = [validateTriggerList];
  80. }
  81. this.validateTrigger = validateTriggerList;
  82. };
  83. Field.prototype.updateFieldRules = function (rules, validateMessages) {
  84. var props = this.ref.getProps();
  85. this.formRules = rules;
  86. this.create(props.name, null, rules[props.name], validateMessages, props.required, props.label, props.message, props.validateTrigger, true);
  87. };
  88. /**
  89. *
  90. * @param rule 修改 Validator
  91. * @param name
  92. * @param required
  93. * @param message
  94. * @param validateMessages
  95. * @returns
  96. */
  97. Field.prototype.transformValidatorRules = function (name, rule, required, label, message, validateMessages) {
  98. var _a, _b;
  99. var requiredRule = false;
  100. var validator;
  101. if (rule) {
  102. var ruleList = Array.isArray(rule) ? rule : [rule];
  103. var result = ruleList.find(function (item) { return item.required; });
  104. if (result) {
  105. if (message) {
  106. result.message = message;
  107. }
  108. requiredRule = true;
  109. }
  110. else if (required) {
  111. ruleList.push({
  112. required: required,
  113. // message 不允许为 null
  114. message: message !== null && message !== void 0 ? message : undefined,
  115. });
  116. requiredRule = true;
  117. }
  118. validator = new AsyncValidator((_a = {},
  119. _a[name] = ruleList,
  120. _a));
  121. }
  122. else if (required) {
  123. validator = new AsyncValidator((_b = {},
  124. _b[name] = {
  125. required: required,
  126. // message 不允许为 null
  127. message: message !== null && message !== void 0 ? message : undefined,
  128. },
  129. _b));
  130. requiredRule = true;
  131. }
  132. if (validator) {
  133. var obj_1 = {
  134. label: label,
  135. };
  136. Object.keys(validator.rules).forEach(function (name) {
  137. validator.rules[name].forEach(function (item) {
  138. if (typeof item.len !== 'undefined') {
  139. obj_1['len'] = item.len;
  140. }
  141. if (typeof item.min !== 'undefined') {
  142. obj_1['min'] = item.min;
  143. }
  144. if (typeof item.max !== 'undefined') {
  145. obj_1['max'] = item.max;
  146. }
  147. if (typeof item.pattern !== 'undefined') {
  148. obj_1['pattern'] = item.pattern;
  149. }
  150. });
  151. });
  152. validator.messages(this.transformValidateMessages(validateMessages, obj_1));
  153. }
  154. this.validator = validator;
  155. return requiredRule;
  156. };
  157. Field.prototype.transformValidateMessages = function (validateMessages, obj) {
  158. if (!validateMessages) {
  159. return;
  160. }
  161. function replaceLabel(validateMessages, target) {
  162. Object.keys(validateMessages).forEach(function (item) {
  163. if (typeof validateMessages[item] === 'string') {
  164. target[item] = validateMessages[item].replace('${label}', obj.label || '');
  165. if (typeof obj.len !== 'undefined') {
  166. target[item] = target[item].replace('${len}', obj.len);
  167. }
  168. if (typeof obj.min !== 'undefined') {
  169. target[item] = target[item].replace('${min}', obj.min);
  170. }
  171. if (typeof obj.max !== 'undefined') {
  172. target[item] = target[item].replace('${max}', obj.max);
  173. }
  174. if (typeof obj.pattern !== 'undefined') {
  175. target[item] = target[item].replace('${pattern}', obj.pattern);
  176. }
  177. return;
  178. }
  179. if (typeof validateMessages[item] === 'object') {
  180. var val = (target[item] = {});
  181. replaceLabel(validateMessages[item], val);
  182. return;
  183. }
  184. target[item] = validateMessages[item];
  185. });
  186. }
  187. var messages = {};
  188. replaceLabel(validateMessages, messages);
  189. return messages;
  190. };
  191. /**
  192. * 设置 Field 值
  193. * @param value Field 值
  194. */
  195. Field.prototype.setValue = function (value) {
  196. this.ref.setFormData({
  197. value: value,
  198. });
  199. };
  200. /**
  201. * 得到 Field 值
  202. */
  203. Field.prototype.getValue = function () {
  204. var value = this.ref.getFormData().value;
  205. return value;
  206. };
  207. /**
  208. * 设置 Field 校验器状态
  209. * @param validatorStatue
  210. */
  211. Field.prototype.setValidatorStatus = function (validatorStatue) {
  212. this.ref.setFormData(validatorStatue);
  213. };
  214. /**
  215. * 得到 Field 校验器状态
  216. * @returns
  217. */
  218. Field.prototype.getValidatorStatus = function () {
  219. var _a = this.ref.getFormData(), status = _a.status, errors = _a.errors;
  220. return {
  221. status: status,
  222. errors: errors,
  223. };
  224. };
  225. /**
  226. * 校验 Field
  227. */
  228. Field.prototype.validate = function () {
  229. return __awaiter(this, void 0, void 0, function () {
  230. var validatorStatusSuccess, value, validator, needUpdateStatus_1, err_1, errors, validatorStatus;
  231. var _a;
  232. var _this = this;
  233. return __generator(this, function (_b) {
  234. switch (_b.label) {
  235. case 0:
  236. validatorStatusSuccess = {
  237. status: 'success',
  238. errors: [],
  239. };
  240. value = this.getValue();
  241. if (!this.validator) {
  242. this.setValidatorStatus(validatorStatusSuccess);
  243. return [2 /*return*/, {
  244. validatorStatus: validatorStatusSuccess,
  245. value: value,
  246. }];
  247. }
  248. validator = this.validator;
  249. _b.label = 1;
  250. case 1:
  251. _b.trys.push([1, 3, , 4]);
  252. needUpdateStatus_1 = true;
  253. Promise.resolve().then(function () {
  254. Promise.resolve().then(function () {
  255. if (needUpdateStatus_1) {
  256. _this.setValidatorStatus({
  257. status: 'validating',
  258. errors: [],
  259. });
  260. }
  261. });
  262. });
  263. return [4 /*yield*/, this.validator.validate((_a = {},
  264. _a[this.name] = value,
  265. _a), function () {
  266. needUpdateStatus_1 = false;
  267. })];
  268. case 2:
  269. _b.sent();
  270. if (validator !== this.validator) {
  271. return [2 /*return*/];
  272. }
  273. this.setValidatorStatus(validatorStatusSuccess);
  274. return [2 /*return*/, {
  275. validatorStatus: validatorStatusSuccess,
  276. value: value,
  277. }];
  278. case 3:
  279. err_1 = _b.sent();
  280. if (validator !== this.validator) {
  281. return [2 /*return*/];
  282. }
  283. errors = err_1.errors;
  284. validatorStatus = {
  285. status: 'error',
  286. errors: errors.map(function (_a) {
  287. var _b = _a.message, message = _b === void 0 ? '' : _b;
  288. return message;
  289. }),
  290. };
  291. this.setValidatorStatus(validatorStatus);
  292. return [2 /*return*/, {
  293. validatorStatus: validatorStatus,
  294. value: value,
  295. }];
  296. case 4: return [2 /*return*/];
  297. }
  298. });
  299. });
  300. };
  301. /**
  302. * 重置 Field
  303. * @param initialValue
  304. */
  305. Field.prototype.reset = function (initialValue) {
  306. this.touched = false;
  307. this.ref.setFormData({
  308. value: initialValue,
  309. required: this.required,
  310. status: 'default',
  311. errors: [],
  312. });
  313. };
  314. /**
  315. * Field 是否被操作
  316. */
  317. Field.prototype.isTouched = function () {
  318. return this.touched;
  319. };
  320. return Field;
  321. }(EventEmitter));
  322. var Form = /** @class */ (function () {
  323. /**
  324. * Form构建
  325. * @param formConfig 表单配置项
  326. */
  327. function Form(formConfig) {
  328. if (formConfig === void 0) { formConfig = {}; }
  329. /**
  330. * 表单ref组件对象
  331. */
  332. this.fields = {};
  333. /**
  334. * 表单字段 change侦听
  335. */
  336. this.changeListeners = [];
  337. /**
  338. * 依赖表
  339. */
  340. this.dependenciesMap = {};
  341. this.setInitialValues(formConfig.initialValues || {});
  342. this.setRules(formConfig.rules || {});
  343. this.validateMessages = formConfig.validateMessages;
  344. }
  345. /**
  346. * 用户传入的rules转换成async-validator rules
  347. * @param rules 校验规则
  348. */
  349. Form.prototype.transformRules = function (rules) {
  350. var _this = this;
  351. var result = {};
  352. Object.keys(rules).forEach(function (name) {
  353. var rule = rules[name];
  354. var list = (result[name] = []);
  355. var arr = Array.isArray(rule) ? rule : [rule];
  356. arr.forEach(function (item) {
  357. if (typeof item === 'function') {
  358. list.push(item(_this).validator);
  359. }
  360. else {
  361. list.push(__assign({}, item));
  362. }
  363. });
  364. });
  365. return result;
  366. };
  367. /**
  368. * 遍历表单field对象
  369. * @param callback
  370. */
  371. Form.prototype.eachField = function (callback) {
  372. var fields = this.fields;
  373. Object.keys(fields).forEach(function (name) {
  374. var field = fields[name];
  375. callback(field, name);
  376. });
  377. };
  378. /**
  379. * 更新 rules
  380. * @param rules
  381. */
  382. Form.prototype.updateRules = function (rules) {
  383. var _this = this;
  384. var rawRules = this.transformRules(rules);
  385. this.rules = rawRules;
  386. Object.keys(this.fields).forEach(function (name) {
  387. _this.fields[name].updateFieldRules(rawRules, _this.validateMessages);
  388. });
  389. };
  390. /**
  391. * 设置 rules
  392. * @param rules
  393. */
  394. Form.prototype.setRules = function (rules) {
  395. this.rules = this.transformRules(rules);
  396. };
  397. /**
  398. * 添加表单对象
  399. * @param ref 表单ref对象
  400. */
  401. Form.prototype.addItem = function (ref, customName) {
  402. var _this = this;
  403. var props = ref.getProps();
  404. var name = customName || props.name;
  405. if (!name) {
  406. ref.on(function (trigger, value) {
  407. if (trigger === 'deriveDataFromProps') {
  408. if (value.name) {
  409. _this.addItem(ref, value.name);
  410. }
  411. }
  412. });
  413. return;
  414. }
  415. if (this.fields[name]) {
  416. throw new Error("Form \"addItem\" same name: \"".concat(name, "\""));
  417. }
  418. var field = new Field(ref, name, this.initialValues, this.rules, this.validateMessages, props.required, props.label, props.message, props.validateTrigger);
  419. if (props.dependencies) {
  420. props.dependencies.forEach(function (item) {
  421. _this.dependenciesMap[item] = _this.dependenciesMap[item] || [];
  422. if (_this.dependenciesMap[item].indexOf(name) < 0) {
  423. _this.dependenciesMap[item].push(name);
  424. }
  425. });
  426. }
  427. field
  428. .on('valueChange', function (value) {
  429. if (name) {
  430. var arr = _this.dependenciesMap[name];
  431. if (arr) {
  432. arr.forEach(function (item) {
  433. if (_this.fields[item]) {
  434. _this.fields[item].validate();
  435. }
  436. });
  437. }
  438. _this.changeListeners.forEach(function (item) {
  439. var _a;
  440. return item((_a = {},
  441. _a[name] = value,
  442. _a), _this.getFieldsValue());
  443. });
  444. }
  445. })
  446. .on('didUnmount', function () {
  447. delete _this.fields[name];
  448. })
  449. .on('replaceName', function (newName) {
  450. if (!newName) {
  451. delete _this.fields[name];
  452. return;
  453. }
  454. if (_this.fields[newName]) {
  455. throw new Error("Form \"addItem\" same name: \"".concat(newName, "\""));
  456. }
  457. _this.fields[newName] = field;
  458. delete _this.fields[name];
  459. name = newName;
  460. });
  461. if (name) {
  462. this.fields[name] = field;
  463. }
  464. };
  465. /**
  466. * 设置表单值
  467. * @param name 表单名称
  468. * @param value 表单初始值
  469. */
  470. Form.prototype.setFieldValue = function (name, value) {
  471. var field = this.fields[name];
  472. if (field) {
  473. field.setValue(value);
  474. field.setValidatorStatus({
  475. status: 'success',
  476. errors: [],
  477. });
  478. }
  479. };
  480. /**
  481. * 设置表单值
  482. * @param name 表单名称
  483. * @param value 表单初始值
  484. */
  485. Form.prototype.setFieldsValue = function (values) {
  486. var _this = this;
  487. Object.keys(values).forEach(function (name) {
  488. _this.setFieldValue(name, values[name]);
  489. });
  490. };
  491. /**
  492. * 设置 initialValues,这个操作不会对页面进行修改,要是需要重置表单可跟上 reset 方法;
  493. * 这样是对于表单已经在编辑,但是需要重新initialValues的场景
  494. *
  495. * eg:
  496. * this.setInitialValues(initialValues);
  497. * this.reset();
  498. *
  499. * @param initialValues
  500. */
  501. Form.prototype.setInitialValues = function (initialValues) {
  502. this.initialValues = initialValues;
  503. };
  504. /**
  505. * 获取对应字段名的值
  506. * @param name
  507. * @returns
  508. */
  509. Form.prototype.getFieldValue = function (name) {
  510. var field = this.fields[name];
  511. if (!field) {
  512. return;
  513. }
  514. return field.getValue();
  515. };
  516. /**
  517. * 获取一组字段名对应的值
  518. * @param nameList
  519. * @returns
  520. */
  521. Form.prototype.getFieldsValue = function (nameList) {
  522. var _this = this;
  523. var fieldsValue = {};
  524. nameList = nameList || Object.keys(this.fields);
  525. nameList.forEach(function (name) {
  526. fieldsValue[name] = _this.getFieldValue(name);
  527. });
  528. return fieldsValue;
  529. };
  530. /**
  531. * 获取对应字段名的校验器状态
  532. * @param name
  533. * @returns
  534. */
  535. Form.prototype.getFieldValidatorStatus = function (name) {
  536. var field = this.fields[name];
  537. if (!field) {
  538. return;
  539. }
  540. return field.getValidatorStatus();
  541. };
  542. /**
  543. * 获取一组字段名的校验器状态
  544. * @param nameList
  545. * @returns
  546. */
  547. Form.prototype.getFieldsValidatorStatus = function (nameList) {
  548. var _this = this;
  549. var fieldsValidatorStatus = {};
  550. nameList = nameList || Object.keys(this.fields);
  551. nameList.forEach(function (name) {
  552. fieldsValidatorStatus[name] = _this.getFieldValidatorStatus(name);
  553. });
  554. return fieldsValidatorStatus;
  555. };
  556. /**
  557. * 设置对应字段名的校验器状态
  558. * @param name 表单名称
  559. * @param validatorStatus 校验状态
  560. * @returns
  561. */
  562. Form.prototype.setFieldValidatorStatus = function (name, validatorStatus) {
  563. var field = this.fields[name];
  564. if (!field) {
  565. return;
  566. }
  567. return field.setValidatorStatus(validatorStatus);
  568. };
  569. /**
  570. * 设置一组字段名的校验器状态
  571. * @param fieldsValidatorStatus 表单校验状态
  572. * @returns
  573. */
  574. Form.prototype.setFieldsValidatorStatus = function (fieldsValidatorStatus) {
  575. var _this = this;
  576. Object.keys(fieldsValidatorStatus).forEach(function (name) {
  577. _this.setFieldValidatorStatus(name, fieldsValidatorStatus[name]);
  578. });
  579. };
  580. /**
  581. * 检查对应字段是否被用户操作过
  582. * @param name 字段名称
  583. * @returns
  584. */
  585. Form.prototype.isFieldTouched = function (name) {
  586. var field = this.fields[name];
  587. if (!field) {
  588. return false;
  589. }
  590. return field.isTouched();
  591. };
  592. /**
  593. * 指定表单字段值更新时触发回调方法
  594. * @param name 表单字段名称
  595. * @param callback 回调方法
  596. */
  597. Form.prototype.onValueChange = function (name, callback) {
  598. this.changeListeners.push(function (changedValues, allValues) {
  599. if (name in changedValues) {
  600. callback(changedValues[name], allValues);
  601. }
  602. });
  603. };
  604. /**
  605. * 表单字段值更新时触发回调方法
  606. * @param name 表单字段名称
  607. * @param callback 回调方法
  608. */
  609. Form.prototype.onValuesChange = function (callback) {
  610. this.changeListeners.push(function (changedValues, allValues) {
  611. callback(changedValues, allValues);
  612. });
  613. };
  614. /**
  615. * 表单提交
  616. */
  617. Form.prototype.submit = function () {
  618. return __awaiter(this, void 0, void 0, function () {
  619. var values, arr, result, errorFields;
  620. var _this = this;
  621. return __generator(this, function (_a) {
  622. switch (_a.label) {
  623. case 0:
  624. values = {};
  625. arr = [];
  626. this.eachField(function (field, name) {
  627. arr.push((function () { return __awaiter(_this, void 0, void 0, function () {
  628. var _a;
  629. return __generator(this, function (_b) {
  630. switch (_b.label) {
  631. case 0:
  632. _a = [{}];
  633. return [4 /*yield*/, field.validate()];
  634. case 1: return [2 /*return*/, __assign.apply(void 0, [__assign.apply(void 0, _a.concat([(_b.sent())])), { name: name }])];
  635. }
  636. });
  637. }); })());
  638. });
  639. return [4 /*yield*/, Promise.all(arr)];
  640. case 1:
  641. result = _a.sent();
  642. errorFields = [];
  643. result.forEach(function (obj) {
  644. if (!obj) {
  645. return;
  646. }
  647. var name = obj.name, value = obj.value, validatorStatus = obj.validatorStatus;
  648. if (validatorStatus.status === 'error') {
  649. errorFields.push({
  650. name: name,
  651. errors: validatorStatus.errors,
  652. });
  653. }
  654. values[name] = value;
  655. });
  656. if (errorFields.length > 0) {
  657. throw {
  658. values: values,
  659. errorFields: errorFields,
  660. };
  661. }
  662. return [2 /*return*/, values];
  663. }
  664. });
  665. });
  666. };
  667. /**
  668. * 表单重置
  669. */
  670. Form.prototype.reset = function () {
  671. var _this = this;
  672. this.eachField(function (field, name) {
  673. var initialValue = _this.initialValues[name];
  674. field.reset(initialValue);
  675. });
  676. };
  677. return Form;
  678. }());
  679. export { Form };
  680. export function createForm(_a) {
  681. var _b = _a === void 0 ? {} : _a, _c = _b.methods, methods = _c === void 0 ? {} : _c;
  682. return {
  683. data: {
  684. formData: {
  685. value: undefined,
  686. status: 'default',
  687. errors: [],
  688. },
  689. },
  690. didUnmount: function () {
  691. this.emit('didUnmount');
  692. },
  693. deriveDataFromProps: function (nextProps) {
  694. this.emit('deriveDataFromProps', nextProps);
  695. },
  696. methods: __assign({ emit: function (trigger, value) { }, setFormData: function (values) {
  697. this.setData(__assign(__assign({}, this.data), { formData: __assign(__assign({}, this.data.formData), values) }));
  698. }, getFormData: function () {
  699. return this.data.formData;
  700. }, on: function (callback) {
  701. this.emit = callback;
  702. }, getProps: function () {
  703. return this.props;
  704. } }, methods),
  705. };
  706. }