useForm.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  3. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = exports.FormStore = void 0;
  8. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  9. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  10. var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
  11. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  12. var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
  13. var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
  14. var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
  15. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  16. var _set = require("rc-util/lib/utils/set");
  17. var _warning = _interopRequireDefault(require("rc-util/lib/warning"));
  18. var React = _interopRequireWildcard(require("react"));
  19. var _FieldContext = require("./FieldContext");
  20. var _asyncUtil = require("./utils/asyncUtil");
  21. var _messages = require("./utils/messages");
  22. var _NameMap = _interopRequireDefault(require("./utils/NameMap"));
  23. var _valueUtil = require("./utils/valueUtil");
  24. var _excluded = ["name"];
  25. var FormStore = exports.FormStore = /*#__PURE__*/(0, _createClass2.default)(function FormStore(forceRootUpdate) {
  26. var _this = this;
  27. (0, _classCallCheck2.default)(this, FormStore);
  28. (0, _defineProperty2.default)(this, "formHooked", false);
  29. (0, _defineProperty2.default)(this, "forceRootUpdate", void 0);
  30. (0, _defineProperty2.default)(this, "subscribable", true);
  31. (0, _defineProperty2.default)(this, "store", {});
  32. (0, _defineProperty2.default)(this, "fieldEntities", []);
  33. (0, _defineProperty2.default)(this, "initialValues", {});
  34. (0, _defineProperty2.default)(this, "callbacks", {});
  35. (0, _defineProperty2.default)(this, "validateMessages", null);
  36. (0, _defineProperty2.default)(this, "preserve", null);
  37. (0, _defineProperty2.default)(this, "lastValidatePromise", null);
  38. (0, _defineProperty2.default)(this, "getForm", function () {
  39. return {
  40. getFieldValue: _this.getFieldValue,
  41. getFieldsValue: _this.getFieldsValue,
  42. getFieldError: _this.getFieldError,
  43. getFieldWarning: _this.getFieldWarning,
  44. getFieldsError: _this.getFieldsError,
  45. isFieldsTouched: _this.isFieldsTouched,
  46. isFieldTouched: _this.isFieldTouched,
  47. isFieldValidating: _this.isFieldValidating,
  48. isFieldsValidating: _this.isFieldsValidating,
  49. resetFields: _this.resetFields,
  50. setFields: _this.setFields,
  51. setFieldValue: _this.setFieldValue,
  52. setFieldsValue: _this.setFieldsValue,
  53. validateFields: _this.validateFields,
  54. submit: _this.submit,
  55. _init: true,
  56. getInternalHooks: _this.getInternalHooks
  57. };
  58. });
  59. // ======================== Internal Hooks ========================
  60. (0, _defineProperty2.default)(this, "getInternalHooks", function (key) {
  61. if (key === _FieldContext.HOOK_MARK) {
  62. _this.formHooked = true;
  63. return {
  64. dispatch: _this.dispatch,
  65. initEntityValue: _this.initEntityValue,
  66. registerField: _this.registerField,
  67. useSubscribe: _this.useSubscribe,
  68. setInitialValues: _this.setInitialValues,
  69. destroyForm: _this.destroyForm,
  70. setCallbacks: _this.setCallbacks,
  71. setValidateMessages: _this.setValidateMessages,
  72. getFields: _this.getFields,
  73. setPreserve: _this.setPreserve,
  74. getInitialValue: _this.getInitialValue,
  75. registerWatch: _this.registerWatch
  76. };
  77. }
  78. (0, _warning.default)(false, '`getInternalHooks` is internal usage. Should not call directly.');
  79. return null;
  80. });
  81. (0, _defineProperty2.default)(this, "useSubscribe", function (subscribable) {
  82. _this.subscribable = subscribable;
  83. });
  84. /**
  85. * Record prev Form unmount fieldEntities which config preserve false.
  86. * This need to be refill with initialValues instead of store value.
  87. */
  88. (0, _defineProperty2.default)(this, "prevWithoutPreserves", null);
  89. /**
  90. * First time `setInitialValues` should update store with initial value
  91. */
  92. (0, _defineProperty2.default)(this, "setInitialValues", function (initialValues, init) {
  93. _this.initialValues = initialValues || {};
  94. if (init) {
  95. var _this$prevWithoutPres;
  96. var nextStore = (0, _set.merge)(initialValues, _this.store);
  97. // We will take consider prev form unmount fields.
  98. // When the field is not `preserve`, we need fill this with initialValues instead of store.
  99. // eslint-disable-next-line array-callback-return
  100. (_this$prevWithoutPres = _this.prevWithoutPreserves) === null || _this$prevWithoutPres === void 0 || _this$prevWithoutPres.map(function (_ref) {
  101. var namePath = _ref.key;
  102. nextStore = (0, _valueUtil.setValue)(nextStore, namePath, (0, _valueUtil.getValue)(initialValues, namePath));
  103. });
  104. _this.prevWithoutPreserves = null;
  105. _this.updateStore(nextStore);
  106. }
  107. });
  108. (0, _defineProperty2.default)(this, "destroyForm", function (clearOnDestroy) {
  109. if (clearOnDestroy) {
  110. // destroy form reset store
  111. _this.updateStore({});
  112. } else {
  113. // Fill preserve fields
  114. var prevWithoutPreserves = new _NameMap.default();
  115. _this.getFieldEntities(true).forEach(function (entity) {
  116. if (!_this.isMergedPreserve(entity.isPreserve())) {
  117. prevWithoutPreserves.set(entity.getNamePath(), true);
  118. }
  119. });
  120. _this.prevWithoutPreserves = prevWithoutPreserves;
  121. }
  122. });
  123. (0, _defineProperty2.default)(this, "getInitialValue", function (namePath) {
  124. var initValue = (0, _valueUtil.getValue)(_this.initialValues, namePath);
  125. // Not cloneDeep when without `namePath`
  126. return namePath.length ? (0, _set.merge)(initValue) : initValue;
  127. });
  128. (0, _defineProperty2.default)(this, "setCallbacks", function (callbacks) {
  129. _this.callbacks = callbacks;
  130. });
  131. (0, _defineProperty2.default)(this, "setValidateMessages", function (validateMessages) {
  132. _this.validateMessages = validateMessages;
  133. });
  134. (0, _defineProperty2.default)(this, "setPreserve", function (preserve) {
  135. _this.preserve = preserve;
  136. });
  137. // ============================= Watch ============================
  138. (0, _defineProperty2.default)(this, "watchList", []);
  139. (0, _defineProperty2.default)(this, "registerWatch", function (callback) {
  140. _this.watchList.push(callback);
  141. return function () {
  142. _this.watchList = _this.watchList.filter(function (fn) {
  143. return fn !== callback;
  144. });
  145. };
  146. });
  147. (0, _defineProperty2.default)(this, "notifyWatch", function () {
  148. var namePath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  149. // No need to cost perf when nothing need to watch
  150. if (_this.watchList.length) {
  151. var values = _this.getFieldsValue();
  152. var allValues = _this.getFieldsValue(true);
  153. _this.watchList.forEach(function (callback) {
  154. callback(values, allValues, namePath);
  155. });
  156. }
  157. });
  158. // ========================== Dev Warning =========================
  159. (0, _defineProperty2.default)(this, "timeoutId", null);
  160. (0, _defineProperty2.default)(this, "warningUnhooked", function () {
  161. if (process.env.NODE_ENV !== 'production' && !_this.timeoutId && typeof window !== 'undefined') {
  162. _this.timeoutId = setTimeout(function () {
  163. _this.timeoutId = null;
  164. if (!_this.formHooked) {
  165. (0, _warning.default)(false, 'Instance created by `useForm` is not connected to any Form element. Forget to pass `form` prop?');
  166. }
  167. });
  168. }
  169. });
  170. // ============================ Store =============================
  171. (0, _defineProperty2.default)(this, "updateStore", function (nextStore) {
  172. _this.store = nextStore;
  173. });
  174. // ============================ Fields ============================
  175. /**
  176. * Get registered field entities.
  177. * @param pure Only return field which has a `name`. Default: false
  178. */
  179. (0, _defineProperty2.default)(this, "getFieldEntities", function () {
  180. var pure = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  181. if (!pure) {
  182. return _this.fieldEntities;
  183. }
  184. return _this.fieldEntities.filter(function (field) {
  185. return field.getNamePath().length;
  186. });
  187. });
  188. (0, _defineProperty2.default)(this, "getFieldsMap", function () {
  189. var pure = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  190. var cache = new _NameMap.default();
  191. _this.getFieldEntities(pure).forEach(function (field) {
  192. var namePath = field.getNamePath();
  193. cache.set(namePath, field);
  194. });
  195. return cache;
  196. });
  197. (0, _defineProperty2.default)(this, "getFieldEntitiesForNamePathList", function (nameList) {
  198. if (!nameList) {
  199. return _this.getFieldEntities(true);
  200. }
  201. var cache = _this.getFieldsMap(true);
  202. return nameList.map(function (name) {
  203. var namePath = (0, _valueUtil.getNamePath)(name);
  204. return cache.get(namePath) || {
  205. INVALIDATE_NAME_PATH: (0, _valueUtil.getNamePath)(name)
  206. };
  207. });
  208. });
  209. (0, _defineProperty2.default)(this, "getFieldsValue", function (nameList, filterFunc) {
  210. _this.warningUnhooked();
  211. // Fill args
  212. var mergedNameList;
  213. var mergedFilterFunc;
  214. var mergedStrict;
  215. if (nameList === true || Array.isArray(nameList)) {
  216. mergedNameList = nameList;
  217. mergedFilterFunc = filterFunc;
  218. } else if (nameList && (0, _typeof2.default)(nameList) === 'object') {
  219. mergedStrict = nameList.strict;
  220. mergedFilterFunc = nameList.filter;
  221. }
  222. if (mergedNameList === true && !mergedFilterFunc) {
  223. return _this.store;
  224. }
  225. var fieldEntities = _this.getFieldEntitiesForNamePathList(Array.isArray(mergedNameList) ? mergedNameList : null);
  226. var filteredNameList = [];
  227. fieldEntities.forEach(function (entity) {
  228. var _isListField, _ref3;
  229. var namePath = 'INVALIDATE_NAME_PATH' in entity ? entity.INVALIDATE_NAME_PATH : entity.getNamePath();
  230. // Ignore when it's a list item and not specific the namePath,
  231. // since parent field is already take in count
  232. if (mergedStrict) {
  233. var _isList, _ref2;
  234. if ((_isList = (_ref2 = entity).isList) !== null && _isList !== void 0 && _isList.call(_ref2)) {
  235. return;
  236. }
  237. } else if (!mergedNameList && (_isListField = (_ref3 = entity).isListField) !== null && _isListField !== void 0 && _isListField.call(_ref3)) {
  238. return;
  239. }
  240. if (!mergedFilterFunc) {
  241. filteredNameList.push(namePath);
  242. } else {
  243. var meta = 'getMeta' in entity ? entity.getMeta() : null;
  244. if (mergedFilterFunc(meta)) {
  245. filteredNameList.push(namePath);
  246. }
  247. }
  248. });
  249. return (0, _valueUtil.cloneByNamePathList)(_this.store, filteredNameList.map(_valueUtil.getNamePath));
  250. });
  251. (0, _defineProperty2.default)(this, "getFieldValue", function (name) {
  252. _this.warningUnhooked();
  253. var namePath = (0, _valueUtil.getNamePath)(name);
  254. return (0, _valueUtil.getValue)(_this.store, namePath);
  255. });
  256. (0, _defineProperty2.default)(this, "getFieldsError", function (nameList) {
  257. _this.warningUnhooked();
  258. var fieldEntities = _this.getFieldEntitiesForNamePathList(nameList);
  259. return fieldEntities.map(function (entity, index) {
  260. if (entity && !('INVALIDATE_NAME_PATH' in entity)) {
  261. return {
  262. name: entity.getNamePath(),
  263. errors: entity.getErrors(),
  264. warnings: entity.getWarnings()
  265. };
  266. }
  267. return {
  268. name: (0, _valueUtil.getNamePath)(nameList[index]),
  269. errors: [],
  270. warnings: []
  271. };
  272. });
  273. });
  274. (0, _defineProperty2.default)(this, "getFieldError", function (name) {
  275. _this.warningUnhooked();
  276. var namePath = (0, _valueUtil.getNamePath)(name);
  277. var fieldError = _this.getFieldsError([namePath])[0];
  278. return fieldError.errors;
  279. });
  280. (0, _defineProperty2.default)(this, "getFieldWarning", function (name) {
  281. _this.warningUnhooked();
  282. var namePath = (0, _valueUtil.getNamePath)(name);
  283. var fieldError = _this.getFieldsError([namePath])[0];
  284. return fieldError.warnings;
  285. });
  286. (0, _defineProperty2.default)(this, "isFieldsTouched", function () {
  287. _this.warningUnhooked();
  288. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  289. args[_key] = arguments[_key];
  290. }
  291. var arg0 = args[0],
  292. arg1 = args[1];
  293. var namePathList;
  294. var isAllFieldsTouched = false;
  295. if (args.length === 0) {
  296. namePathList = null;
  297. } else if (args.length === 1) {
  298. if (Array.isArray(arg0)) {
  299. namePathList = arg0.map(_valueUtil.getNamePath);
  300. isAllFieldsTouched = false;
  301. } else {
  302. namePathList = null;
  303. isAllFieldsTouched = arg0;
  304. }
  305. } else {
  306. namePathList = arg0.map(_valueUtil.getNamePath);
  307. isAllFieldsTouched = arg1;
  308. }
  309. var fieldEntities = _this.getFieldEntities(true);
  310. var isFieldTouched = function isFieldTouched(field) {
  311. return field.isFieldTouched();
  312. };
  313. // ===== Will get fully compare when not config namePathList =====
  314. if (!namePathList) {
  315. return isAllFieldsTouched ? fieldEntities.every(function (entity) {
  316. return isFieldTouched(entity) || entity.isList();
  317. }) : fieldEntities.some(isFieldTouched);
  318. }
  319. // Generate a nest tree for validate
  320. var map = new _NameMap.default();
  321. namePathList.forEach(function (shortNamePath) {
  322. map.set(shortNamePath, []);
  323. });
  324. fieldEntities.forEach(function (field) {
  325. var fieldNamePath = field.getNamePath();
  326. // Find matched entity and put into list
  327. namePathList.forEach(function (shortNamePath) {
  328. if (shortNamePath.every(function (nameUnit, i) {
  329. return fieldNamePath[i] === nameUnit;
  330. })) {
  331. map.update(shortNamePath, function (list) {
  332. return [].concat((0, _toConsumableArray2.default)(list), [field]);
  333. });
  334. }
  335. });
  336. });
  337. // Check if NameMap value is touched
  338. var isNamePathListTouched = function isNamePathListTouched(entities) {
  339. return entities.some(isFieldTouched);
  340. };
  341. var namePathListEntities = map.map(function (_ref4) {
  342. var value = _ref4.value;
  343. return value;
  344. });
  345. return isAllFieldsTouched ? namePathListEntities.every(isNamePathListTouched) : namePathListEntities.some(isNamePathListTouched);
  346. });
  347. (0, _defineProperty2.default)(this, "isFieldTouched", function (name) {
  348. _this.warningUnhooked();
  349. return _this.isFieldsTouched([name]);
  350. });
  351. (0, _defineProperty2.default)(this, "isFieldsValidating", function (nameList) {
  352. _this.warningUnhooked();
  353. var fieldEntities = _this.getFieldEntities();
  354. if (!nameList) {
  355. return fieldEntities.some(function (testField) {
  356. return testField.isFieldValidating();
  357. });
  358. }
  359. var namePathList = nameList.map(_valueUtil.getNamePath);
  360. return fieldEntities.some(function (testField) {
  361. var fieldNamePath = testField.getNamePath();
  362. return (0, _valueUtil.containsNamePath)(namePathList, fieldNamePath) && testField.isFieldValidating();
  363. });
  364. });
  365. (0, _defineProperty2.default)(this, "isFieldValidating", function (name) {
  366. _this.warningUnhooked();
  367. return _this.isFieldsValidating([name]);
  368. });
  369. /**
  370. * Reset Field with field `initialValue` prop.
  371. * Can pass `entities` or `namePathList` or just nothing.
  372. */
  373. (0, _defineProperty2.default)(this, "resetWithFieldInitialValue", function () {
  374. var info = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  375. // Create cache
  376. var cache = new _NameMap.default();
  377. var fieldEntities = _this.getFieldEntities(true);
  378. fieldEntities.forEach(function (field) {
  379. var initialValue = field.props.initialValue;
  380. var namePath = field.getNamePath();
  381. // Record only if has `initialValue`
  382. if (initialValue !== undefined) {
  383. var records = cache.get(namePath) || new Set();
  384. records.add({
  385. entity: field,
  386. value: initialValue
  387. });
  388. cache.set(namePath, records);
  389. }
  390. });
  391. // Reset
  392. var resetWithFields = function resetWithFields(entities) {
  393. entities.forEach(function (field) {
  394. var initialValue = field.props.initialValue;
  395. if (initialValue !== undefined) {
  396. var namePath = field.getNamePath();
  397. var formInitialValue = _this.getInitialValue(namePath);
  398. if (formInitialValue !== undefined) {
  399. // Warning if conflict with form initialValues and do not modify value
  400. (0, _warning.default)(false, "Form already set 'initialValues' with path '".concat(namePath.join('.'), "'. Field can not overwrite it."));
  401. } else {
  402. var records = cache.get(namePath);
  403. if (records && records.size > 1) {
  404. // Warning if multiple field set `initialValue`and do not modify value
  405. (0, _warning.default)(false, "Multiple Field with path '".concat(namePath.join('.'), "' set 'initialValue'. Can not decide which one to pick."));
  406. } else if (records) {
  407. var originValue = _this.getFieldValue(namePath);
  408. var isListField = field.isListField();
  409. // Set `initialValue`
  410. if (!isListField && (!info.skipExist || originValue === undefined)) {
  411. _this.updateStore((0, _valueUtil.setValue)(_this.store, namePath, (0, _toConsumableArray2.default)(records)[0].value));
  412. }
  413. }
  414. }
  415. }
  416. });
  417. };
  418. var requiredFieldEntities;
  419. if (info.entities) {
  420. requiredFieldEntities = info.entities;
  421. } else if (info.namePathList) {
  422. requiredFieldEntities = [];
  423. info.namePathList.forEach(function (namePath) {
  424. var records = cache.get(namePath);
  425. if (records) {
  426. var _requiredFieldEntitie;
  427. (_requiredFieldEntitie = requiredFieldEntities).push.apply(_requiredFieldEntitie, (0, _toConsumableArray2.default)((0, _toConsumableArray2.default)(records).map(function (r) {
  428. return r.entity;
  429. })));
  430. }
  431. });
  432. } else {
  433. requiredFieldEntities = fieldEntities;
  434. }
  435. resetWithFields(requiredFieldEntities);
  436. });
  437. (0, _defineProperty2.default)(this, "resetFields", function (nameList) {
  438. _this.warningUnhooked();
  439. var prevStore = _this.store;
  440. if (!nameList) {
  441. _this.updateStore((0, _set.merge)(_this.initialValues));
  442. _this.resetWithFieldInitialValue();
  443. _this.notifyObservers(prevStore, null, {
  444. type: 'reset'
  445. });
  446. _this.notifyWatch();
  447. return;
  448. }
  449. // Reset by `nameList`
  450. var namePathList = nameList.map(_valueUtil.getNamePath);
  451. namePathList.forEach(function (namePath) {
  452. var initialValue = _this.getInitialValue(namePath);
  453. _this.updateStore((0, _valueUtil.setValue)(_this.store, namePath, initialValue));
  454. });
  455. _this.resetWithFieldInitialValue({
  456. namePathList: namePathList
  457. });
  458. _this.notifyObservers(prevStore, namePathList, {
  459. type: 'reset'
  460. });
  461. _this.notifyWatch(namePathList);
  462. });
  463. (0, _defineProperty2.default)(this, "setFields", function (fields) {
  464. _this.warningUnhooked();
  465. var prevStore = _this.store;
  466. var namePathList = [];
  467. fields.forEach(function (fieldData) {
  468. var name = fieldData.name,
  469. data = (0, _objectWithoutProperties2.default)(fieldData, _excluded);
  470. var namePath = (0, _valueUtil.getNamePath)(name);
  471. namePathList.push(namePath);
  472. // Value
  473. if ('value' in data) {
  474. _this.updateStore((0, _valueUtil.setValue)(_this.store, namePath, data.value));
  475. }
  476. _this.notifyObservers(prevStore, [namePath], {
  477. type: 'setField',
  478. data: fieldData
  479. });
  480. });
  481. _this.notifyWatch(namePathList);
  482. });
  483. (0, _defineProperty2.default)(this, "getFields", function () {
  484. var entities = _this.getFieldEntities(true);
  485. var fields = entities.map(function (field) {
  486. var namePath = field.getNamePath();
  487. var meta = field.getMeta();
  488. var fieldData = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, meta), {}, {
  489. name: namePath,
  490. value: _this.getFieldValue(namePath)
  491. });
  492. Object.defineProperty(fieldData, 'originRCField', {
  493. value: true
  494. });
  495. return fieldData;
  496. });
  497. return fields;
  498. });
  499. // =========================== Observer ===========================
  500. /**
  501. * This only trigger when a field is on constructor to avoid we get initialValue too late
  502. */
  503. (0, _defineProperty2.default)(this, "initEntityValue", function (entity) {
  504. var initialValue = entity.props.initialValue;
  505. if (initialValue !== undefined) {
  506. var namePath = entity.getNamePath();
  507. var prevValue = (0, _valueUtil.getValue)(_this.store, namePath);
  508. if (prevValue === undefined) {
  509. _this.updateStore((0, _valueUtil.setValue)(_this.store, namePath, initialValue));
  510. }
  511. }
  512. });
  513. (0, _defineProperty2.default)(this, "isMergedPreserve", function (fieldPreserve) {
  514. var mergedPreserve = fieldPreserve !== undefined ? fieldPreserve : _this.preserve;
  515. return mergedPreserve !== null && mergedPreserve !== void 0 ? mergedPreserve : true;
  516. });
  517. (0, _defineProperty2.default)(this, "registerField", function (entity) {
  518. _this.fieldEntities.push(entity);
  519. var namePath = entity.getNamePath();
  520. _this.notifyWatch([namePath]);
  521. // Set initial values
  522. if (entity.props.initialValue !== undefined) {
  523. var prevStore = _this.store;
  524. _this.resetWithFieldInitialValue({
  525. entities: [entity],
  526. skipExist: true
  527. });
  528. _this.notifyObservers(prevStore, [entity.getNamePath()], {
  529. type: 'valueUpdate',
  530. source: 'internal'
  531. });
  532. }
  533. // un-register field callback
  534. return function (isListField, preserve) {
  535. var subNamePath = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  536. _this.fieldEntities = _this.fieldEntities.filter(function (item) {
  537. return item !== entity;
  538. });
  539. // Clean up store value if not preserve
  540. if (!_this.isMergedPreserve(preserve) && (!isListField || subNamePath.length > 1)) {
  541. var defaultValue = isListField ? undefined : _this.getInitialValue(namePath);
  542. if (namePath.length && _this.getFieldValue(namePath) !== defaultValue && _this.fieldEntities.every(function (field) {
  543. return (
  544. // Only reset when no namePath exist
  545. !(0, _valueUtil.matchNamePath)(field.getNamePath(), namePath)
  546. );
  547. })) {
  548. var _prevStore = _this.store;
  549. _this.updateStore((0, _valueUtil.setValue)(_prevStore, namePath, defaultValue, true));
  550. // Notify that field is unmount
  551. _this.notifyObservers(_prevStore, [namePath], {
  552. type: 'remove'
  553. });
  554. // Dependencies update
  555. _this.triggerDependenciesUpdate(_prevStore, namePath);
  556. }
  557. }
  558. _this.notifyWatch([namePath]);
  559. };
  560. });
  561. (0, _defineProperty2.default)(this, "dispatch", function (action) {
  562. switch (action.type) {
  563. case 'updateValue':
  564. {
  565. var namePath = action.namePath,
  566. value = action.value;
  567. _this.updateValue(namePath, value);
  568. break;
  569. }
  570. case 'validateField':
  571. {
  572. var _namePath = action.namePath,
  573. triggerName = action.triggerName;
  574. _this.validateFields([_namePath], {
  575. triggerName: triggerName
  576. });
  577. break;
  578. }
  579. default:
  580. // Currently we don't have other action. Do nothing.
  581. }
  582. });
  583. (0, _defineProperty2.default)(this, "notifyObservers", function (prevStore, namePathList, info) {
  584. if (_this.subscribable) {
  585. var mergedInfo = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, info), {}, {
  586. store: _this.getFieldsValue(true)
  587. });
  588. _this.getFieldEntities().forEach(function (_ref5) {
  589. var onStoreChange = _ref5.onStoreChange;
  590. onStoreChange(prevStore, namePathList, mergedInfo);
  591. });
  592. } else {
  593. _this.forceRootUpdate();
  594. }
  595. });
  596. /**
  597. * Notify dependencies children with parent update
  598. * We need delay to trigger validate in case Field is under render props
  599. */
  600. (0, _defineProperty2.default)(this, "triggerDependenciesUpdate", function (prevStore, namePath) {
  601. var childrenFields = _this.getDependencyChildrenFields(namePath);
  602. if (childrenFields.length) {
  603. _this.validateFields(childrenFields);
  604. }
  605. _this.notifyObservers(prevStore, childrenFields, {
  606. type: 'dependenciesUpdate',
  607. relatedFields: [namePath].concat((0, _toConsumableArray2.default)(childrenFields))
  608. });
  609. return childrenFields;
  610. });
  611. (0, _defineProperty2.default)(this, "updateValue", function (name, value) {
  612. var namePath = (0, _valueUtil.getNamePath)(name);
  613. var prevStore = _this.store;
  614. _this.updateStore((0, _valueUtil.setValue)(_this.store, namePath, value));
  615. _this.notifyObservers(prevStore, [namePath], {
  616. type: 'valueUpdate',
  617. source: 'internal'
  618. });
  619. _this.notifyWatch([namePath]);
  620. // Dependencies update
  621. var childrenFields = _this.triggerDependenciesUpdate(prevStore, namePath);
  622. // trigger callback function
  623. var onValuesChange = _this.callbacks.onValuesChange;
  624. if (onValuesChange) {
  625. var changedValues = (0, _valueUtil.cloneByNamePathList)(_this.store, [namePath]);
  626. onValuesChange(changedValues, _this.getFieldsValue());
  627. }
  628. _this.triggerOnFieldsChange([namePath].concat((0, _toConsumableArray2.default)(childrenFields)));
  629. });
  630. // Let all child Field get update.
  631. (0, _defineProperty2.default)(this, "setFieldsValue", function (store) {
  632. _this.warningUnhooked();
  633. var prevStore = _this.store;
  634. if (store) {
  635. var nextStore = (0, _set.merge)(_this.store, store);
  636. _this.updateStore(nextStore);
  637. }
  638. _this.notifyObservers(prevStore, null, {
  639. type: 'valueUpdate',
  640. source: 'external'
  641. });
  642. _this.notifyWatch();
  643. });
  644. (0, _defineProperty2.default)(this, "setFieldValue", function (name, value) {
  645. _this.setFields([{
  646. name: name,
  647. value: value,
  648. errors: [],
  649. warnings: []
  650. }]);
  651. });
  652. (0, _defineProperty2.default)(this, "getDependencyChildrenFields", function (rootNamePath) {
  653. var children = new Set();
  654. var childrenFields = [];
  655. var dependencies2fields = new _NameMap.default();
  656. /**
  657. * Generate maps
  658. * Can use cache to save perf if user report performance issue with this
  659. */
  660. _this.getFieldEntities().forEach(function (field) {
  661. var dependencies = field.props.dependencies;
  662. (dependencies || []).forEach(function (dependency) {
  663. var dependencyNamePath = (0, _valueUtil.getNamePath)(dependency);
  664. dependencies2fields.update(dependencyNamePath, function () {
  665. var fields = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Set();
  666. fields.add(field);
  667. return fields;
  668. });
  669. });
  670. });
  671. var fillChildren = function fillChildren(namePath) {
  672. var fields = dependencies2fields.get(namePath) || new Set();
  673. fields.forEach(function (field) {
  674. if (!children.has(field)) {
  675. children.add(field);
  676. var fieldNamePath = field.getNamePath();
  677. if (field.isFieldDirty() && fieldNamePath.length) {
  678. childrenFields.push(fieldNamePath);
  679. fillChildren(fieldNamePath);
  680. }
  681. }
  682. });
  683. };
  684. fillChildren(rootNamePath);
  685. return childrenFields;
  686. });
  687. (0, _defineProperty2.default)(this, "triggerOnFieldsChange", function (namePathList, filedErrors) {
  688. var onFieldsChange = _this.callbacks.onFieldsChange;
  689. if (onFieldsChange) {
  690. var fields = _this.getFields();
  691. /**
  692. * Fill errors since `fields` may be replaced by controlled fields
  693. */
  694. if (filedErrors) {
  695. var cache = new _NameMap.default();
  696. filedErrors.forEach(function (_ref6) {
  697. var name = _ref6.name,
  698. errors = _ref6.errors;
  699. cache.set(name, errors);
  700. });
  701. fields.forEach(function (field) {
  702. // eslint-disable-next-line no-param-reassign
  703. field.errors = cache.get(field.name) || field.errors;
  704. });
  705. }
  706. var changedFields = fields.filter(function (_ref7) {
  707. var fieldName = _ref7.name;
  708. return (0, _valueUtil.containsNamePath)(namePathList, fieldName);
  709. });
  710. if (changedFields.length) {
  711. onFieldsChange(changedFields, fields);
  712. }
  713. }
  714. });
  715. // =========================== Validate ===========================
  716. (0, _defineProperty2.default)(this, "validateFields", function (arg1, arg2) {
  717. _this.warningUnhooked();
  718. var nameList;
  719. var options;
  720. if (Array.isArray(arg1) || typeof arg1 === 'string' || typeof arg2 === 'string') {
  721. nameList = arg1;
  722. options = arg2;
  723. } else {
  724. options = arg1;
  725. }
  726. var provideNameList = !!nameList;
  727. var namePathList = provideNameList ? nameList.map(_valueUtil.getNamePath) : [];
  728. // Collect result in promise list
  729. var promiseList = [];
  730. // We temp save the path which need trigger for `onFieldsChange`
  731. var TMP_SPLIT = String(Date.now());
  732. var validateNamePathList = new Set();
  733. var _ref8 = options || {},
  734. recursive = _ref8.recursive,
  735. dirty = _ref8.dirty;
  736. _this.getFieldEntities(true).forEach(function (field) {
  737. // Add field if not provide `nameList`
  738. if (!provideNameList) {
  739. namePathList.push(field.getNamePath());
  740. }
  741. // Skip if without rule
  742. if (!field.props.rules || !field.props.rules.length) {
  743. return;
  744. }
  745. // Skip if only validate dirty field
  746. if (dirty && !field.isFieldDirty()) {
  747. return;
  748. }
  749. var fieldNamePath = field.getNamePath();
  750. validateNamePathList.add(fieldNamePath.join(TMP_SPLIT));
  751. // Add field validate rule in to promise list
  752. if (!provideNameList || (0, _valueUtil.containsNamePath)(namePathList, fieldNamePath, recursive)) {
  753. var promise = field.validateRules((0, _objectSpread2.default)({
  754. validateMessages: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _messages.defaultValidateMessages), _this.validateMessages)
  755. }, options));
  756. // Wrap promise with field
  757. promiseList.push(promise.then(function () {
  758. return {
  759. name: fieldNamePath,
  760. errors: [],
  761. warnings: []
  762. };
  763. }).catch(function (ruleErrors) {
  764. var _ruleErrors$forEach;
  765. var mergedErrors = [];
  766. var mergedWarnings = [];
  767. (_ruleErrors$forEach = ruleErrors.forEach) === null || _ruleErrors$forEach === void 0 || _ruleErrors$forEach.call(ruleErrors, function (_ref9) {
  768. var warningOnly = _ref9.rule.warningOnly,
  769. errors = _ref9.errors;
  770. if (warningOnly) {
  771. mergedWarnings.push.apply(mergedWarnings, (0, _toConsumableArray2.default)(errors));
  772. } else {
  773. mergedErrors.push.apply(mergedErrors, (0, _toConsumableArray2.default)(errors));
  774. }
  775. });
  776. if (mergedErrors.length) {
  777. return Promise.reject({
  778. name: fieldNamePath,
  779. errors: mergedErrors,
  780. warnings: mergedWarnings
  781. });
  782. }
  783. return {
  784. name: fieldNamePath,
  785. errors: mergedErrors,
  786. warnings: mergedWarnings
  787. };
  788. }));
  789. }
  790. });
  791. var summaryPromise = (0, _asyncUtil.allPromiseFinish)(promiseList);
  792. _this.lastValidatePromise = summaryPromise;
  793. // Notify fields with rule that validate has finished and need update
  794. summaryPromise.catch(function (results) {
  795. return results;
  796. }).then(function (results) {
  797. var resultNamePathList = results.map(function (_ref10) {
  798. var name = _ref10.name;
  799. return name;
  800. });
  801. _this.notifyObservers(_this.store, resultNamePathList, {
  802. type: 'validateFinish'
  803. });
  804. _this.triggerOnFieldsChange(resultNamePathList, results);
  805. });
  806. var returnPromise = summaryPromise.then(function () {
  807. if (_this.lastValidatePromise === summaryPromise) {
  808. return Promise.resolve(_this.getFieldsValue(namePathList));
  809. }
  810. return Promise.reject([]);
  811. }).catch(function (results) {
  812. var errorList = results.filter(function (result) {
  813. return result && result.errors.length;
  814. });
  815. return Promise.reject({
  816. values: _this.getFieldsValue(namePathList),
  817. errorFields: errorList,
  818. outOfDate: _this.lastValidatePromise !== summaryPromise
  819. });
  820. });
  821. // Do not throw in console
  822. returnPromise.catch(function (e) {
  823. return e;
  824. });
  825. // `validating` changed. Trigger `onFieldsChange`
  826. var triggerNamePathList = namePathList.filter(function (namePath) {
  827. return validateNamePathList.has(namePath.join(TMP_SPLIT));
  828. });
  829. _this.triggerOnFieldsChange(triggerNamePathList);
  830. return returnPromise;
  831. });
  832. // ============================ Submit ============================
  833. (0, _defineProperty2.default)(this, "submit", function () {
  834. _this.warningUnhooked();
  835. _this.validateFields().then(function (values) {
  836. var onFinish = _this.callbacks.onFinish;
  837. if (onFinish) {
  838. try {
  839. onFinish(values);
  840. } catch (err) {
  841. // Should print error if user `onFinish` callback failed
  842. console.error(err);
  843. }
  844. }
  845. }).catch(function (e) {
  846. var onFinishFailed = _this.callbacks.onFinishFailed;
  847. if (onFinishFailed) {
  848. onFinishFailed(e);
  849. }
  850. });
  851. });
  852. this.forceRootUpdate = forceRootUpdate;
  853. });
  854. function useForm(form) {
  855. var formRef = React.useRef();
  856. var _React$useState = React.useState({}),
  857. _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
  858. forceUpdate = _React$useState2[1];
  859. if (!formRef.current) {
  860. if (form) {
  861. formRef.current = form;
  862. } else {
  863. // Create a new FormStore if not provided
  864. var forceReRender = function forceReRender() {
  865. forceUpdate({});
  866. };
  867. var formStore = new FormStore(forceReRender);
  868. formRef.current = formStore.getForm();
  869. }
  870. }
  871. return [formRef.current];
  872. }
  873. var _default = exports.default = useForm;