form.js 25 KB

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