Form.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.formProps = exports.default = void 0;
  7. var _vue = require("vue");
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  10. var _vueTypes = _interopRequireDefault(require("../_util/vue-types"));
  11. var _classNames = _interopRequireDefault(require("../_util/classNames"));
  12. var _warning = _interopRequireDefault(require("../_util/warning"));
  13. var _FormItem = _interopRequireDefault(require("./FormItem"));
  14. var _valueUtil = require("./utils/valueUtil");
  15. var _messages = require("./utils/messages");
  16. var _asyncUtil = require("./utils/asyncUtil");
  17. var _typeUtil = require("./utils/typeUtil");
  18. var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
  19. var _scrollIntoViewIfNeeded = _interopRequireDefault(require("scroll-into-view-if-needed"));
  20. var _initDefaultProps = _interopRequireDefault(require("../_util/props-util/initDefaultProps"));
  21. var _type = require("../_util/type");
  22. var _useConfigInject = _interopRequireDefault(require("../config-provider/hooks/useConfigInject"));
  23. var _context = require("./context");
  24. var _useForm = _interopRequireDefault(require("./useForm"));
  25. var _context2 = require("../config-provider/context");
  26. var _style = _interopRequireDefault(require("./style"));
  27. var _SizeContext = require("../config-provider/SizeContext");
  28. var _DisabledContext = require("../config-provider/DisabledContext");
  29. const formProps = () => ({
  30. layout: _vueTypes.default.oneOf((0, _type.tuple)('horizontal', 'inline', 'vertical')),
  31. labelCol: (0, _type.objectType)(),
  32. wrapperCol: (0, _type.objectType)(),
  33. colon: (0, _type.booleanType)(),
  34. labelAlign: (0, _type.stringType)(),
  35. labelWrap: (0, _type.booleanType)(),
  36. prefixCls: String,
  37. requiredMark: (0, _type.someType)([String, Boolean]),
  38. /** @deprecated Will warning in future branch. Pls use `requiredMark` instead. */
  39. hideRequiredMark: (0, _type.booleanType)(),
  40. model: _vueTypes.default.object,
  41. rules: (0, _type.objectType)(),
  42. validateMessages: (0, _type.objectType)(),
  43. validateOnRuleChange: (0, _type.booleanType)(),
  44. // 提交失败自动滚动到第一个错误字段
  45. scrollToFirstError: (0, _type.anyType)(),
  46. onSubmit: (0, _type.functionType)(),
  47. name: String,
  48. validateTrigger: (0, _type.someType)([String, Array]),
  49. size: (0, _type.stringType)(),
  50. disabled: (0, _type.booleanType)(),
  51. onValuesChange: (0, _type.functionType)(),
  52. onFieldsChange: (0, _type.functionType)(),
  53. onFinish: (0, _type.functionType)(),
  54. onFinishFailed: (0, _type.functionType)(),
  55. onValidate: (0, _type.functionType)()
  56. });
  57. exports.formProps = formProps;
  58. function isEqualName(name1, name2) {
  59. return (0, _isEqual.default)((0, _typeUtil.toArray)(name1), (0, _typeUtil.toArray)(name2));
  60. }
  61. const Form = (0, _vue.defineComponent)({
  62. compatConfig: {
  63. MODE: 3
  64. },
  65. name: 'AForm',
  66. inheritAttrs: false,
  67. props: (0, _initDefaultProps.default)(formProps(), {
  68. layout: 'horizontal',
  69. hideRequiredMark: false,
  70. colon: true
  71. }),
  72. Item: _FormItem.default,
  73. useForm: _useForm.default,
  74. // emits: ['finishFailed', 'submit', 'finish', 'validate'],
  75. setup(props, _ref) {
  76. let {
  77. emit,
  78. slots,
  79. expose,
  80. attrs
  81. } = _ref;
  82. const {
  83. prefixCls,
  84. direction,
  85. form: contextForm,
  86. size,
  87. disabled
  88. } = (0, _useConfigInject.default)('form', props);
  89. const requiredMark = (0, _vue.computed)(() => props.requiredMark === '' || props.requiredMark);
  90. const mergedRequiredMark = (0, _vue.computed)(() => {
  91. var _a;
  92. if (requiredMark.value !== undefined) {
  93. return requiredMark.value;
  94. }
  95. if (contextForm && ((_a = contextForm.value) === null || _a === void 0 ? void 0 : _a.requiredMark) !== undefined) {
  96. return contextForm.value.requiredMark;
  97. }
  98. if (props.hideRequiredMark) {
  99. return false;
  100. }
  101. return true;
  102. });
  103. (0, _SizeContext.useProviderSize)(size);
  104. (0, _DisabledContext.useProviderDisabled)(disabled);
  105. const mergedColon = (0, _vue.computed)(() => {
  106. var _a, _b;
  107. return (_a = props.colon) !== null && _a !== void 0 ? _a : (_b = contextForm.value) === null || _b === void 0 ? void 0 : _b.colon;
  108. });
  109. const {
  110. validateMessages: globalValidateMessages
  111. } = (0, _context2.useInjectGlobalForm)();
  112. const validateMessages = (0, _vue.computed)(() => {
  113. return (0, _extends2.default)((0, _extends2.default)((0, _extends2.default)({}, _messages.defaultValidateMessages), globalValidateMessages.value), props.validateMessages);
  114. });
  115. // Style
  116. const [wrapSSR, hashId] = (0, _style.default)(prefixCls);
  117. const formClassName = (0, _vue.computed)(() => (0, _classNames.default)(prefixCls.value, {
  118. [`${prefixCls.value}-${props.layout}`]: true,
  119. [`${prefixCls.value}-hide-required-mark`]: mergedRequiredMark.value === false,
  120. [`${prefixCls.value}-rtl`]: direction.value === 'rtl',
  121. [`${prefixCls.value}-${size.value}`]: size.value
  122. }, hashId.value));
  123. const lastValidatePromise = (0, _vue.ref)();
  124. const fields = {};
  125. const addField = (eventKey, field) => {
  126. fields[eventKey] = field;
  127. };
  128. const removeField = eventKey => {
  129. delete fields[eventKey];
  130. };
  131. const getFieldsByNameList = nameList => {
  132. const provideNameList = !!nameList;
  133. const namePathList = provideNameList ? (0, _typeUtil.toArray)(nameList).map(_valueUtil.getNamePath) : [];
  134. if (!provideNameList) {
  135. return Object.values(fields);
  136. } else {
  137. return Object.values(fields).filter(field => namePathList.findIndex(namePath => isEqualName(namePath, field.fieldName.value)) > -1);
  138. }
  139. };
  140. const resetFields = name => {
  141. if (!props.model) {
  142. (0, _warning.default)(false, 'Form', 'model is required for resetFields to work.');
  143. return;
  144. }
  145. getFieldsByNameList(name).forEach(field => {
  146. field.resetField();
  147. });
  148. };
  149. const clearValidate = name => {
  150. getFieldsByNameList(name).forEach(field => {
  151. field.clearValidate();
  152. });
  153. };
  154. const handleFinishFailed = errorInfo => {
  155. const {
  156. scrollToFirstError
  157. } = props;
  158. emit('finishFailed', errorInfo);
  159. if (scrollToFirstError && errorInfo.errorFields.length) {
  160. let scrollToFieldOptions = {};
  161. if (typeof scrollToFirstError === 'object') {
  162. scrollToFieldOptions = scrollToFirstError;
  163. }
  164. scrollToField(errorInfo.errorFields[0].name, scrollToFieldOptions);
  165. }
  166. };
  167. const validate = function () {
  168. return validateField(...arguments);
  169. };
  170. const scrollToField = function (name) {
  171. let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  172. const fields = getFieldsByNameList(name ? [name] : undefined);
  173. if (fields.length) {
  174. const fieldId = fields[0].fieldId.value;
  175. const node = fieldId ? document.getElementById(fieldId) : null;
  176. if (node) {
  177. (0, _scrollIntoViewIfNeeded.default)(node, (0, _extends2.default)({
  178. scrollMode: 'if-needed',
  179. block: 'nearest'
  180. }, options));
  181. }
  182. }
  183. };
  184. // eslint-disable-next-line no-unused-vars
  185. const getFieldsValue = function () {
  186. let nameList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
  187. if (nameList === true) {
  188. const allNameList = [];
  189. Object.values(fields).forEach(_ref2 => {
  190. let {
  191. namePath
  192. } = _ref2;
  193. allNameList.push(namePath.value);
  194. });
  195. return (0, _valueUtil.cloneByNamePathList)(props.model, allNameList);
  196. } else {
  197. return (0, _valueUtil.cloneByNamePathList)(props.model, nameList);
  198. }
  199. };
  200. const validateFields = (nameList, options) => {
  201. (0, _warning.default)(!(nameList instanceof Function), 'Form', 'validateFields/validateField/validate not support callback, please use promise instead');
  202. if (!props.model) {
  203. (0, _warning.default)(false, 'Form', 'model is required for validateFields to work.');
  204. return Promise.reject('Form `model` is required for validateFields to work.');
  205. }
  206. const provideNameList = !!nameList;
  207. const namePathList = provideNameList ? (0, _typeUtil.toArray)(nameList).map(_valueUtil.getNamePath) : [];
  208. // Collect result in promise list
  209. const promiseList = [];
  210. Object.values(fields).forEach(field => {
  211. var _a;
  212. // Add field if not provide `nameList`
  213. if (!provideNameList) {
  214. namePathList.push(field.namePath.value);
  215. }
  216. // Skip if without rule
  217. if (!((_a = field.rules) === null || _a === void 0 ? void 0 : _a.value.length)) {
  218. return;
  219. }
  220. const fieldNamePath = field.namePath.value;
  221. // Add field validate rule in to promise list
  222. if (!provideNameList || (0, _valueUtil.containsNamePath)(namePathList, fieldNamePath)) {
  223. const promise = field.validateRules((0, _extends2.default)({
  224. validateMessages: validateMessages.value
  225. }, options));
  226. // Wrap promise with field
  227. promiseList.push(promise.then(() => ({
  228. name: fieldNamePath,
  229. errors: [],
  230. warnings: []
  231. })).catch(ruleErrors => {
  232. const mergedErrors = [];
  233. const mergedWarnings = [];
  234. ruleErrors.forEach(_ref3 => {
  235. let {
  236. rule: {
  237. warningOnly
  238. },
  239. errors
  240. } = _ref3;
  241. if (warningOnly) {
  242. mergedWarnings.push(...errors);
  243. } else {
  244. mergedErrors.push(...errors);
  245. }
  246. });
  247. if (mergedErrors.length) {
  248. return Promise.reject({
  249. name: fieldNamePath,
  250. errors: mergedErrors,
  251. warnings: mergedWarnings
  252. });
  253. }
  254. return {
  255. name: fieldNamePath,
  256. errors: mergedErrors,
  257. warnings: mergedWarnings
  258. };
  259. }));
  260. }
  261. });
  262. const summaryPromise = (0, _asyncUtil.allPromiseFinish)(promiseList);
  263. lastValidatePromise.value = summaryPromise;
  264. const returnPromise = summaryPromise.then(() => {
  265. if (lastValidatePromise.value === summaryPromise) {
  266. return Promise.resolve(getFieldsValue(namePathList));
  267. }
  268. return Promise.reject([]);
  269. }).catch(results => {
  270. const errorList = results.filter(result => result && result.errors.length);
  271. return Promise.reject({
  272. values: getFieldsValue(namePathList),
  273. errorFields: errorList,
  274. outOfDate: lastValidatePromise.value !== summaryPromise
  275. });
  276. });
  277. // Do not throw in console
  278. returnPromise.catch(e => e);
  279. return returnPromise;
  280. };
  281. const validateField = function () {
  282. return validateFields(...arguments);
  283. };
  284. const handleSubmit = e => {
  285. e.preventDefault();
  286. e.stopPropagation();
  287. emit('submit', e);
  288. if (props.model) {
  289. const res = validateFields();
  290. res.then(values => {
  291. emit('finish', values);
  292. }).catch(errors => {
  293. handleFinishFailed(errors);
  294. });
  295. }
  296. };
  297. expose({
  298. resetFields,
  299. clearValidate,
  300. validateFields,
  301. getFieldsValue,
  302. validate,
  303. scrollToField
  304. });
  305. (0, _context.useProvideForm)({
  306. model: (0, _vue.computed)(() => props.model),
  307. name: (0, _vue.computed)(() => props.name),
  308. labelAlign: (0, _vue.computed)(() => props.labelAlign),
  309. labelCol: (0, _vue.computed)(() => props.labelCol),
  310. labelWrap: (0, _vue.computed)(() => props.labelWrap),
  311. wrapperCol: (0, _vue.computed)(() => props.wrapperCol),
  312. vertical: (0, _vue.computed)(() => props.layout === 'vertical'),
  313. colon: mergedColon,
  314. requiredMark: mergedRequiredMark,
  315. validateTrigger: (0, _vue.computed)(() => props.validateTrigger),
  316. rules: (0, _vue.computed)(() => props.rules),
  317. addField,
  318. removeField,
  319. onValidate: (name, status, errors) => {
  320. emit('validate', name, status, errors);
  321. },
  322. validateMessages
  323. });
  324. (0, _vue.watch)(() => props.rules, () => {
  325. if (props.validateOnRuleChange) {
  326. validateFields();
  327. }
  328. });
  329. return () => {
  330. var _a;
  331. return wrapSSR((0, _vue.createVNode)("form", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
  332. "onSubmit": handleSubmit,
  333. "class": [formClassName.value, attrs.class]
  334. }), [(_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)]));
  335. };
  336. }
  337. });
  338. var _default = exports.default = Form;