mobx-form 13.2.1 → 13.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.md ADDED
@@ -0,0 +1,307 @@
1
+
2
+ # mobx-form - Changelog
3
+ ## v13.3.1
4
+ - **Features**
5
+ - add dirty flag and commit method to form - [ebcc44a]( https://github.com/royriojas/mobx-form/commit/ebcc44a ), [Roy Riojas](https://github.com/Roy Riojas), 31/05/2023 17:37:50
6
+
7
+
8
+ ## v13.3.0
9
+ - **Features**
10
+ - add validatedOnce flag - [64cfa58]( https://github.com/royriojas/mobx-form/commit/64cfa58 ), [Roy Riojas](https://github.com/Roy Riojas), 03/02/2023 12:27:36
11
+
12
+
13
+ ## v13.2.1
14
+ - **Other changes**
15
+ - improved typings - [c9fa38e]( https://github.com/royriojas/mobx-form/commit/c9fa38e ), [Roy Riojas](https://github.com/Roy Riojas), 01/02/2023 01:42:51
16
+
17
+
18
+ ## v13.2.0
19
+ - **Other changes**
20
+ - add option to store raw error - [e516ca0]( https://github.com/royriojas/mobx-form/commit/e516ca0 ), [Roy Riojas](https://github.com/Roy Riojas), 26/09/2021 07:49:51
21
+
22
+
23
+ ## v13.1.1
24
+ - **Bug Fixes**
25
+ - fix typings - [973031f]( https://github.com/royriojas/mobx-form/commit/973031f ), [Roy Riojas](https://github.com/Roy Riojas), 14/09/2021 18:38:35
26
+
27
+
28
+ ## v13.1.0
29
+ - **Bug Fixes**
30
+ - add method to mark as interacted - [0b56ae4]( https://github.com/royriojas/mobx-form/commit/0b56ae4 ), [Roy Riojas](https://github.com/Roy Riojas), 14/09/2021 18:35:37
31
+
32
+
33
+ ## v13.0.0
34
+ - **Bug Fixes**
35
+ - include runtime to fix federated issue - [6a6d243]( https://github.com/royriojas/mobx-form/commit/6a6d243 ), [Roy Riojas](https://github.com/Roy Riojas), 13/09/2021 03:13:33
36
+
37
+
38
+ ## v12.0.4
39
+ - **Bug Fixes**
40
+ - update types for updateFrom method - [8187fbc]( https://github.com/royriojas/mobx-form/commit/8187fbc ), [Roy Riojas](https://github.com/Roy Riojas), 29/08/2021 02:04:19
41
+
42
+
43
+ ## v12.0.3
44
+ - **Features**
45
+ - add option to clear the error on value change - [bf370dc]( https://github.com/royriojas/mobx-form/commit/bf370dc ), [Roy Riojas](https://github.com/Roy Riojas), 08/06/2021 01:22:11
46
+
47
+
48
+ ## v12.0.2
49
+ - **Features**
50
+ - Add custom debounce threshold for validator and ignoring of stale validations - [387d4b0]( https://github.com/royriojas/mobx-form/commit/387d4b0 ), [Roy Riojas](https://github.com/Roy Riojas), 08/06/2021 01:10:16
51
+
52
+
53
+ ## v12.0.1
54
+ - **Features**
55
+ - Add better types for validator functions - [9170451]( https://github.com/royriojas/mobx-form/commit/9170451 ), [Roy Riojas](https://github.com/Roy Riojas), 04/06/2021 18:07:55
56
+
57
+
58
+ ## v12.0.0
59
+ - **Features**
60
+ - Add isValidating prop to fields - [6240db6]( https://github.com/royriojas/mobx-form/commit/6240db6 ), [Roy Riojas](https://github.com/Roy Riojas), 26/03/2021 05:21:23
61
+
62
+
63
+ ## v11.0.1
64
+ - **Refactoring**
65
+ - use types instead of typings - [d53d463]( https://github.com/royriojas/mobx-form/commit/d53d463 ), [Roy Riojas](https://github.com/Roy Riojas), 07/02/2021 01:52:43
66
+
67
+
68
+ ## v11.0.0
69
+ - **Bug Fixes**
70
+ - fields with boolean values should be considered empty only if no value is set - [98112c6]( https://github.com/royriojas/mobx-form/commit/98112c6 ), [Roy Riojas](https://github.com/Roy Riojas), 21/01/2021 03:58:25
71
+
72
+
73
+ ## v10.1.2
74
+ - **Bug Fixes**
75
+ - fix TS types - [6c9c250]( https://github.com/royriojas/mobx-form/commit/6c9c250 ), [Roy Riojas](https://github.com/Roy Riojas), 13/01/2021 21:42:54
76
+
77
+
78
+ ## v10.1.1
79
+ - **Refactoring**
80
+ - upgrade deps to latest versions - [d4d2256]( https://github.com/royriojas/mobx-form/commit/d4d2256 ), [Roy Riojas](https://github.com/Roy Riojas), 13/01/2021 18:49:59
81
+
82
+
83
+ ## v10.1.0
84
+ - **Refactoring**
85
+ - add option to not to throw if field is missing - [b51a63c]( https://github.com/royriojas/mobx-form/commit/b51a63c ), [Roy Riojas](https://github.com/Roy Riojas), 13/01/2021 18:28:20
86
+
87
+
88
+ ## v10.0.5
89
+ - **Refactoring**
90
+ - Upgrade typescript types - [e37000c]( https://github.com/royriojas/mobx-form/commit/e37000c ), [Roy Riojas](https://github.com/Roy Riojas), 16/10/2020 01:58:23
91
+
92
+
93
+ ## v10.0.4
94
+ - **Refactoring**
95
+ - Upgrade typescript types - [64610cf]( https://github.com/royriojas/mobx-form/commit/64610cf ), [Roy Riojas](https://github.com/Roy Riojas), 16/10/2020 01:52:30
96
+
97
+
98
+ ## v10.0.3
99
+ - **Refactoring**
100
+ - Upgrade typescript types - [6edfe0f]( https://github.com/royriojas/mobx-form/commit/6edfe0f ), [Roy Riojas](https://github.com/Roy Riojas), 16/10/2020 00:50:18
101
+
102
+
103
+ ## v10.0.2
104
+ - **Refactoring**
105
+ - Upgrade typescript types - [be233df]( https://github.com/royriojas/mobx-form/commit/be233df ), [Roy Riojas](https://github.com/Roy Riojas), 16/10/2020 00:47:04
106
+
107
+
108
+ ## v10.0.1
109
+ - **Refactoring**
110
+ - Upgrade babel runtime dep - [0f6dc9c]( https://github.com/royriojas/mobx-form/commit/0f6dc9c ), [Roy Riojas](https://github.com/Roy Riojas), 15/10/2020 23:23:40
111
+
112
+
113
+ ## v10.0.0
114
+ - **Bug Fixes**
115
+ - fix lint issues - [0bc9c13]( https://github.com/royriojas/mobx-form/commit/0bc9c13 ), [Roy Riojas](https://github.com/Roy Riojas), 15/10/2020 23:19:25
116
+
117
+
118
+ - **Refactoring**
119
+ - Migrate to Mobx@6 - [0c6a711]( https://github.com/royriojas/mobx-form/commit/0c6a711 ), [Roy Riojas](https://github.com/Roy Riojas), 15/10/2020 23:17:17
120
+
121
+
122
+ ## v9.0.7
123
+ - **Refactoring**
124
+ - Add license file to mobx-form - [e25d4b3]( https://github.com/royriojas/mobx-form/commit/e25d4b3 ), [Roy Riojas](https://github.com/Roy Riojas), 04/09/2020 12:52:16
125
+
126
+
127
+ ## v9.0.6
128
+ - **Refactoring**
129
+ - force validation marks the field as blurred - [e520d0c]( https://github.com/royriojas/mobx-form/commit/e520d0c ), [Roy Riojas](https://github.com/Roy Riojas), 14/05/2020 21:59:39
130
+
131
+
132
+ ## v9.0.5
133
+ - **Refactoring**
134
+ - Update tests and typings - [5df9baa]( https://github.com/royriojas/mobx-form/commit/5df9baa ), [Roy Riojas](https://github.com/Roy Riojas), 14/05/2020 21:46:02
135
+
136
+
137
+ ## v9.0.4
138
+ - **Refactoring**
139
+ - Update typings - [994336d]( https://github.com/royriojas/mobx-form/commit/994336d ), [Roy Riojas](https://github.com/Roy Riojas), 14/05/2020 20:16:51
140
+
141
+
142
+ ## v9.0.3
143
+ - **Refactoring**
144
+ - Make the required prop also a string - [8b6995e]( https://github.com/royriojas/mobx-form/commit/8b6995e ), [Roy Riojas](https://github.com/Roy Riojas), 14/05/2020 20:03:02
145
+
146
+
147
+ ## v9.0.1-beta.1
148
+ - **Refactoring**
149
+ - Add typings for mobx-form - [bceb65f]( https://github.com/royriojas/mobx-form/commit/bceb65f ), [Roy Riojas](https://github.com/Roy Riojas), 14/05/2020 19:46:10
150
+
151
+
152
+ ## v9.0.0
153
+ - **Refactoring**
154
+ - Add a minor version change - [e6a016c]( https://github.com/royriojas/mobx-form/commit/e6a016c ), [Roy Riojas](https://github.com/Roy Riojas), 14/05/2020 01:06:33
155
+
156
+
157
+ ## v8.0.0-beta.4
158
+ - **Refactoring**
159
+ - Upgrade beta version - [f467f2e]( https://github.com/royriojas/mobx-form/commit/f467f2e ), [Roy Riojas](https://github.com/Roy Riojas), 13/05/2020 23:27:03
160
+
161
+
162
+ - publish beta-2 version - [9eb8f21]( https://github.com/royriojas/mobx-form/commit/9eb8f21 ), [Roy Riojas](https://github.com/Roy Riojas), 13/05/2020 23:16:39
163
+
164
+
165
+ - bump beta version - [4ad0319]( https://github.com/royriojas/mobx-form/commit/4ad0319 ), [Roy Riojas](https://github.com/Roy Riojas), 13/05/2020 23:05:12
166
+
167
+
168
+ - Upgrade modules - [b88b0d0]( https://github.com/royriojas/mobx-form/commit/b88b0d0 ), [Roy Riojas](https://github.com/Roy Riojas), 13/05/2020 23:03:38
169
+
170
+
171
+ - Add blurredOnce getter - [b9b1309]( https://github.com/royriojas/mobx-form/commit/b9b1309 ), [Roy Riojas](https://github.com/Roy Riojas), 13/05/2020 21:25:42
172
+
173
+
174
+ - Update babel pacakge version - [6a85d4d]( https://github.com/royriojas/mobx-form/commit/6a85d4d ), [Roy Riojas](https://github.com/Roy Riojas), 28/04/2020 01:34:54
175
+
176
+
177
+ - Make use of latest rollup and babel plugins - [6bb8cbd]( https://github.com/royriojas/mobx-form/commit/6bb8cbd ), [Roy Riojas](https://github.com/Roy Riojas), 28/04/2020 01:34:22
178
+
179
+
180
+ ## v8.0.0
181
+ - **Refactoring**
182
+ - Fix lint - [11eb2d6]( https://github.com/royriojas/mobx-form/commit/11eb2d6 ), [royriojas](https://github.com/royriojas), 10/09/2019 09:19:36
183
+
184
+
185
+ - Major refactor on mobx-form and adding tests - [d9b0da0]( https://github.com/royriojas/mobx-form/commit/d9b0da0 ), [royriojas](https://github.com/royriojas), 10/09/2019 09:18:28
186
+
187
+
188
+ ## v7.0.1
189
+ - **Refactoring**
190
+ - remove Observable arrays from serialization of fields - [741487e]( https://github.com/royriojas/mobx-form/commit/741487e ), [royriojas](https://github.com/royriojas), 19/08/2019 18:13:49
191
+
192
+
193
+ ## v7.0.0-alpha.3
194
+ - **Refactoring**
195
+ - Attempt to change browser field to something webpack likes - take 2 - [95783ad]( https://github.com/royriojas/mobx-form/commit/95783ad ), [royriojas](https://github.com/royriojas), 04/08/2019 22:54:02
196
+
197
+
198
+ ## v7.0.0-alpha.2
199
+ - **Refactoring**
200
+ - Attempt to change browser field to something webpack likes - [a7d9d65]( https://github.com/royriojas/mobx-form/commit/a7d9d65 ), [royriojas](https://github.com/royriojas), 04/08/2019 22:50:34
201
+
202
+
203
+ ## v7.0.0-alpha.1
204
+ - **Bug Fixes**
205
+ - Fix lint issues - [b0a850d]( https://github.com/royriojas/mobx-form/commit/b0a850d ), [royriojas](https://github.com/royriojas), 04/08/2019 22:13:30
206
+
207
+
208
+ ## v7.0.0-alpha.0
209
+ - **Refactoring**
210
+ - Simplify and improve mobx-form api - [8f48e28]( https://github.com/royriojas/mobx-form/commit/8f48e28 ), [royriojas](https://github.com/royriojas), 04/08/2019 22:10:29
211
+
212
+
213
+ ## v5.2.2
214
+ - **Refactoring**
215
+ - Upgrade node_modules and use latest babel - [b795e13]( https://github.com/royriojas/mobx-form/commit/b795e13 ), [Roy Riojas](https://github.com/Roy Riojas), 07/05/2019 22:11:58
216
+
217
+ Breaking change as now we transpile 2 versions of the module one for evergreen browsers and one for IE11
218
+
219
+ ## v5.2.1
220
+ - **Refactoring**
221
+ - Add rest spread support - [48ae905]( https://github.com/royriojas/mobx-form/commit/48ae905 ), [Roy Riojas](https://github.com/Roy Riojas), 13/01/2019 18:58:53
222
+
223
+
224
+ ## v5.2.0
225
+ - **Features**
226
+ - Add support to create a form from an array or an object descriptor - [19072dc]( https://github.com/royriojas/mobx-form/commit/19072dc ), [Roy Riojas](https://github.com/Roy Riojas), 13/01/2019 17:51:12
227
+
228
+
229
+ ## v5.0.3
230
+ - **Features**
231
+ - pass the model instance to the validators - [f4045c1]( https://github.com/royriojas/mobx-form/commit/f4045c1 ), [Roy Riojas](https://github.com/Roy Riojas), 20/12/2018 01:50:08
232
+
233
+
234
+ ## v5.0.2
235
+ - **Refactoring**
236
+ - Be compatible with enforceActions option of mobx - [d419fba]( https://github.com/royriojas/mobx-form/commit/d419fba ), [Roy Riojas](https://github.com/Roy Riojas), 17/08/2018 04:10:08
237
+
238
+
239
+ ## v5.0.1
240
+ - **Bug Fixes**
241
+ - wrong entry point for UMD target - [de06c9d]( https://github.com/royriojas/mobx-form/commit/de06c9d ), [Roy Riojas](https://github.com/Roy Riojas), 09/08/2018 20:28:53
242
+
243
+
244
+ ## v5.0.0
245
+ - **Refactoring**
246
+ - remove dependency on regenerator - [e8bdbc9]( https://github.com/royriojas/mobx-form/commit/e8bdbc9 ), [Roy Riojas](https://github.com/Roy Riojas), 09/08/2018 20:27:41
247
+
248
+
249
+ ## v4.0.0
250
+ - **Refactoring**
251
+ - Create a smaller umd bundle - [81d81e3]( https://github.com/royriojas/mobx-form/commit/81d81e3 ), [Roy Riojas](https://github.com/Roy Riojas), 09/08/2018 20:07:12
252
+
253
+
254
+ - **Other changes**
255
+ - Update FormModel.test.js - [bff561e]( https://github.com/royriojas/mobx-form/commit/bff561e ), [Roy Riojas](https://github.com/Roy Riojas), 09/08/2018 19:24:08
256
+
257
+
258
+ ## v3.0.2
259
+ - **Refactoring**
260
+ - Add prepublish script - [f0dde93]( https://github.com/royriojas/mobx-form/commit/f0dde93 ), [Roy Riojas](https://github.com/Roy Riojas), 08/08/2018 19:32:01
261
+
262
+
263
+ ## v3.0.1
264
+ - **Refactoring**
265
+ - rename the bundle output - [49d010d]( https://github.com/royriojas/mobx-form/commit/49d010d ), [Roy Riojas](https://github.com/Roy Riojas), 08/08/2018 19:24:28
266
+
267
+
268
+ ## v3.0.0
269
+ - **Refactoring**
270
+ - Use rollup to create umd/esm/cjs bundles - [697d75c]( https://github.com/royriojas/mobx-form/commit/697d75c ), [Roy Riojas](https://github.com/Roy Riojas), 08/08/2018 12:38:47
271
+
272
+
273
+ ## v2.1.1
274
+ - **Documentation**
275
+ - Fix missing peer dependency - [9feae5e]( https://github.com/royriojas/mobx-form/commit/9feae5e ), [Roy Riojas](https://github.com/Roy Riojas), 08/08/2018 10:57:06
276
+
277
+
278
+ ## v2.1.0
279
+ - **Documentation**
280
+ - update documenation - [7718d79]( https://github.com/royriojas/mobx-form/commit/7718d79 ), [Roy Riojas](https://github.com/Roy Riojas), 08/08/2018 10:16:28
281
+
282
+
283
+ ## v2.0.0
284
+ - **Refactoring**
285
+ - Update FormModel to add new features and tests - [4e449d9]( https://github.com/royriojas/mobx-form/commit/4e449d9 ), [Roy Riojas](https://github.com/Roy Riojas), 08/08/2018 08:28:41
286
+
287
+
288
+ ## v1.0.1
289
+ - **Build Scripts Changes**
290
+ - Add build tasks - [2b36cf5]( https://github.com/royriojas/mobx-form/commit/2b36cf5 ), [Roy Riojas](https://github.com/Roy Riojas), 23/06/2016 18:26:51
291
+
292
+
293
+ - **Refactoring**
294
+ - Add a helper to improve how fields are set - [c208bc7]( https://github.com/royriojas/mobx-form/commit/c208bc7 ), [Roy Riojas](https://github.com/Roy Riojas), 23/06/2016 18:22:35
295
+
296
+
297
+ - **Documentation**
298
+ - add more documentation - [443d90d]( https://github.com/royriojas/mobx-form/commit/443d90d ), [Roy Riojas](https://github.com/Roy Riojas), 15/06/2016 11:02:55
299
+
300
+
301
+ - add missed import - [3da648e]( https://github.com/royriojas/mobx-form/commit/3da648e ), [Roy Riojas](https://github.com/Roy Riojas), 15/06/2016 10:53:32
302
+
303
+
304
+ - **Features**
305
+ - initial version - [02003a4]( https://github.com/royriojas/mobx-form/commit/02003a4 ), [Roy Riojas](https://github.com/Roy Riojas), 15/06/2016 10:49:00
306
+
307
+
@@ -100,6 +100,10 @@ const isNullishOrEmpty = value => typeof value === 'undefined' || value === null
100
100
 
101
101
 
102
102
  class Field {
103
+ get validatedAtLeastOnce() {
104
+ return this._validatedOnce;
105
+ }
106
+
103
107
  get waitForBlur() {
104
108
  return !!this._waitForBlur;
105
109
  }
@@ -121,6 +125,10 @@ class Field {
121
125
  this._interacted = true;
122
126
  }
123
127
 
128
+ resetValidatedOnce() {
129
+ this._validatedOnce = false;
130
+ }
131
+
124
132
  get hasValue() {
125
133
  if (this._hasValueFn) {
126
134
  return this._hasValueFn(this.value);
@@ -260,13 +268,19 @@ class Field {
260
268
 
261
269
 
262
270
  restoreInitialValue({
263
- resetInteractedFlag = true
271
+ resetInteractedFlag = true,
272
+ commit = true
264
273
  } = {}) {
265
274
  this.setValue(this._initialValue, {
266
- resetInteractedFlag
275
+ resetInteractedFlag,
276
+ commit
267
277
  });
268
278
  }
269
279
 
280
+ get dirty() {
281
+ return this._initialValue !== this.value;
282
+ }
283
+
270
284
  commit() {
271
285
  this._initialValue = this.value;
272
286
  }
@@ -359,6 +373,11 @@ class Field {
359
373
  const {
360
374
  required
361
375
  } = this;
376
+
377
+ if (!this._validatedOnce) {
378
+ this._validatedOnce = true;
379
+ }
380
+
362
381
  const shouldSkipValidation = this.disabled || !required && !this._validateFn;
363
382
  if (shouldSkipValidation) return;
364
383
 
@@ -477,6 +496,7 @@ class Field {
477
496
  constructor(model, value, validatorDescriptor = {}, fieldName) {
478
497
  this._disabled = void 0;
479
498
  this._required = void 0;
499
+ this._validatedOnce = false;
480
500
  this._validating = false;
481
501
  this._initialValue = void 0;
482
502
  this._value = void 0;
@@ -509,6 +529,9 @@ class Field {
509
529
  };
510
530
 
511
531
  mobx.makeObservable(this, {
532
+ resetValidatedOnce: mobx.action,
533
+ _validatedOnce: mobx.observable,
534
+ validatedAtLeastOnce: mobx.computed,
512
535
  _disabled: mobx.observable,
513
536
  _required: mobx.observable,
514
537
  waitForBlur: mobx.computed,
@@ -519,8 +542,10 @@ class Field {
519
542
  hasValue: mobx.computed,
520
543
  _autoValidate: mobx.observable,
521
544
  _value: mobx.observable,
545
+ _initialValue: mobx.observable,
522
546
  _interacted: mobx.observable,
523
547
  _blurredOnce: mobx.observable,
548
+ dirty: mobx.computed,
524
549
  blurred: mobx.computed,
525
550
  errorMessage: mobx.computed,
526
551
  rawError: mobx.observable.ref,
@@ -594,6 +619,11 @@ const isObject = o => o && toString.call(o) === '[object Object]';
594
619
 
595
620
 
596
621
  class FormModel {
622
+ get validatedAtLeastOnce() {
623
+ const keys = Object.keys(this.fields);
624
+ return keys.every(key => this.fields[key].validatedAtLeastOnce);
625
+ }
626
+
597
627
  get dataIsReady() {
598
628
  return this.interacted && this.requiredAreFilled && this.valid;
599
629
  }
@@ -653,6 +683,18 @@ class FormModel {
653
683
  restoreInitialValues(opts) {
654
684
  this._eachField(field => field.restoreInitialValue(opts));
655
685
  }
686
+
687
+ commit() {
688
+ this._eachField(field => field.commit());
689
+ }
690
+
691
+ get dirty() {
692
+ return this._fieldKeys().some(key => {
693
+ const f = this._getField(key);
694
+
695
+ return f.dirty;
696
+ });
697
+ }
656
698
  /**
657
699
  * Set multiple values to more than one field a time using an object
658
700
  * where each key is the name of a field. The value will be set to each
@@ -810,6 +852,8 @@ class FormModel {
810
852
  };
811
853
 
812
854
  mobx.makeObservable(this, {
855
+ resetValidatedOnce: mobx.action,
856
+ validatedAtLeastOnce: mobx.computed,
813
857
  dataIsReady: mobx.computed,
814
858
  requiredFields: mobx.computed,
815
859
  requiredAreFilled: mobx.computed,
@@ -828,11 +872,14 @@ class FormModel {
828
872
  resetInteractedFlag: mobx.action,
829
873
  disableFields: mobx.action,
830
874
  addFields: mobx.action,
831
- enableFields: mobx.action
875
+ enableFields: mobx.action,
876
+ commit: mobx.action,
877
+ dirty: mobx.computed
832
878
  });
833
879
  this.addFields(descriptors);
834
880
  initialState && this.updateFrom(initialState, {
835
- throwIfMissingField: options.throwIfMissingField
881
+ throwIfMissingField: options.throwIfMissingField,
882
+ commit: true
836
883
  });
837
884
  }
838
885
 
@@ -888,6 +935,12 @@ class FormModel {
888
935
  });
889
936
  }
890
937
 
938
+ resetValidatedOnce() {
939
+ this._fieldKeys().forEach(key => {
940
+ this.fields[key].resetValidatedOnce();
941
+ });
942
+ }
943
+
891
944
  }
892
945
  /**
893
946
  * return an instance of a FormModel refer to the constructor
@@ -94,6 +94,10 @@ const isNullishOrEmpty = value => typeof value === 'undefined' || value === null
94
94
 
95
95
 
96
96
  class Field {
97
+ get validatedAtLeastOnce() {
98
+ return this._validatedOnce;
99
+ }
100
+
97
101
  get waitForBlur() {
98
102
  return !!this._waitForBlur;
99
103
  }
@@ -115,6 +119,10 @@ class Field {
115
119
  this._interacted = true;
116
120
  }
117
121
 
122
+ resetValidatedOnce() {
123
+ this._validatedOnce = false;
124
+ }
125
+
118
126
  get hasValue() {
119
127
  if (this._hasValueFn) {
120
128
  return this._hasValueFn(this.value);
@@ -254,13 +262,19 @@ class Field {
254
262
 
255
263
 
256
264
  restoreInitialValue({
257
- resetInteractedFlag = true
265
+ resetInteractedFlag = true,
266
+ commit = true
258
267
  } = {}) {
259
268
  this.setValue(this._initialValue, {
260
- resetInteractedFlag
269
+ resetInteractedFlag,
270
+ commit
261
271
  });
262
272
  }
263
273
 
274
+ get dirty() {
275
+ return this._initialValue !== this.value;
276
+ }
277
+
264
278
  commit() {
265
279
  this._initialValue = this.value;
266
280
  }
@@ -353,6 +367,11 @@ class Field {
353
367
  const {
354
368
  required
355
369
  } = this;
370
+
371
+ if (!this._validatedOnce) {
372
+ this._validatedOnce = true;
373
+ }
374
+
356
375
  const shouldSkipValidation = this.disabled || !required && !this._validateFn;
357
376
  if (shouldSkipValidation) return;
358
377
 
@@ -471,6 +490,7 @@ class Field {
471
490
  constructor(model, value, validatorDescriptor = {}, fieldName) {
472
491
  this._disabled = void 0;
473
492
  this._required = void 0;
493
+ this._validatedOnce = false;
474
494
  this._validating = false;
475
495
  this._initialValue = void 0;
476
496
  this._value = void 0;
@@ -503,6 +523,9 @@ class Field {
503
523
  };
504
524
 
505
525
  makeObservable(this, {
526
+ resetValidatedOnce: action,
527
+ _validatedOnce: observable,
528
+ validatedAtLeastOnce: computed,
506
529
  _disabled: observable,
507
530
  _required: observable,
508
531
  waitForBlur: computed,
@@ -513,8 +536,10 @@ class Field {
513
536
  hasValue: computed,
514
537
  _autoValidate: observable,
515
538
  _value: observable,
539
+ _initialValue: observable,
516
540
  _interacted: observable,
517
541
  _blurredOnce: observable,
542
+ dirty: computed,
518
543
  blurred: computed,
519
544
  errorMessage: computed,
520
545
  rawError: observable.ref,
@@ -588,6 +613,11 @@ const isObject = o => o && toString.call(o) === '[object Object]';
588
613
 
589
614
 
590
615
  class FormModel {
616
+ get validatedAtLeastOnce() {
617
+ const keys = Object.keys(this.fields);
618
+ return keys.every(key => this.fields[key].validatedAtLeastOnce);
619
+ }
620
+
591
621
  get dataIsReady() {
592
622
  return this.interacted && this.requiredAreFilled && this.valid;
593
623
  }
@@ -647,6 +677,18 @@ class FormModel {
647
677
  restoreInitialValues(opts) {
648
678
  this._eachField(field => field.restoreInitialValue(opts));
649
679
  }
680
+
681
+ commit() {
682
+ this._eachField(field => field.commit());
683
+ }
684
+
685
+ get dirty() {
686
+ return this._fieldKeys().some(key => {
687
+ const f = this._getField(key);
688
+
689
+ return f.dirty;
690
+ });
691
+ }
650
692
  /**
651
693
  * Set multiple values to more than one field a time using an object
652
694
  * where each key is the name of a field. The value will be set to each
@@ -804,6 +846,8 @@ class FormModel {
804
846
  };
805
847
 
806
848
  makeObservable(this, {
849
+ resetValidatedOnce: action,
850
+ validatedAtLeastOnce: computed,
807
851
  dataIsReady: computed,
808
852
  requiredFields: computed,
809
853
  requiredAreFilled: computed,
@@ -822,11 +866,14 @@ class FormModel {
822
866
  resetInteractedFlag: action,
823
867
  disableFields: action,
824
868
  addFields: action,
825
- enableFields: action
869
+ enableFields: action,
870
+ commit: action,
871
+ dirty: computed
826
872
  });
827
873
  this.addFields(descriptors);
828
874
  initialState && this.updateFrom(initialState, {
829
- throwIfMissingField: options.throwIfMissingField
875
+ throwIfMissingField: options.throwIfMissingField,
876
+ commit: true
830
877
  });
831
878
  }
832
879
 
@@ -882,6 +929,12 @@ class FormModel {
882
929
  });
883
930
  }
884
931
 
932
+ resetValidatedOnce() {
933
+ this._fieldKeys().forEach(key => {
934
+ this.fields[key].resetValidatedOnce();
935
+ });
936
+ }
937
+
885
938
  }
886
939
  /**
887
940
  * return an instance of a FormModel refer to the constructor
@@ -203,6 +203,11 @@ var Field = /*#__PURE__*/function () {
203
203
  value: function markAsInteracted() {
204
204
  this._interacted = true;
205
205
  }
206
+ }, {
207
+ key: "resetValidatedOnce",
208
+ value: function resetValidatedOnce() {
209
+ this._validatedOnce = false;
210
+ }
206
211
  }, {
207
212
  key: "_setValueOnly",
208
213
  value: function _setValueOnly(val) {
@@ -272,10 +277,13 @@ var Field = /*#__PURE__*/function () {
272
277
  value: function restoreInitialValue() {
273
278
  var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
274
279
  _ref2$resetInteracted = _ref2.resetInteractedFlag,
275
- resetInteractedFlag = _ref2$resetInteracted === void 0 ? true : _ref2$resetInteracted;
280
+ resetInteractedFlag = _ref2$resetInteracted === void 0 ? true : _ref2$resetInteracted,
281
+ _ref2$commit = _ref2.commit,
282
+ commit = _ref2$commit === void 0 ? true : _ref2$commit;
276
283
 
277
284
  this.setValue(this._initialValue, {
278
- resetInteractedFlag: resetInteractedFlag
285
+ resetInteractedFlag: resetInteractedFlag,
286
+ commit: commit
279
287
  });
280
288
  }
281
289
  }, {
@@ -434,6 +442,11 @@ var Field = /*#__PURE__*/function () {
434
442
  force = _ref3$force === void 0 ? false : _ref3$force;
435
443
 
436
444
  var required = this.required;
445
+
446
+ if (!this._validatedOnce) {
447
+ this._validatedOnce = true;
448
+ }
449
+
437
450
  var shouldSkipValidation = this.disabled || !required && !this._validateFn;
438
451
  if (shouldSkipValidation) return;
439
452
 
@@ -551,6 +564,11 @@ var Field = /*#__PURE__*/function () {
551
564
  value: function setError(error) {
552
565
  this.rawError = error;
553
566
  }
567
+ }, {
568
+ key: "validatedAtLeastOnce",
569
+ get: function get() {
570
+ return this._validatedOnce;
571
+ }
554
572
  }, {
555
573
  key: "waitForBlur",
556
574
  get: function get() {
@@ -653,6 +671,11 @@ var Field = /*#__PURE__*/function () {
653
671
  set: function set(val) {
654
672
  this._setValue(val);
655
673
  }
674
+ }, {
675
+ key: "dirty",
676
+ get: function get() {
677
+ return this._initialValue !== this.value;
678
+ }
656
679
  }, {
657
680
  key: "originalErrorMessage",
658
681
  get: function get() {
@@ -680,6 +703,7 @@ var Field = /*#__PURE__*/function () {
680
703
 
681
704
  this._disabled = void 0;
682
705
  this._required = void 0;
706
+ this._validatedOnce = false;
683
707
  this._validating = false;
684
708
  this._initialValue = void 0;
685
709
  this._value = void 0;
@@ -712,6 +736,9 @@ var Field = /*#__PURE__*/function () {
712
736
  };
713
737
 
714
738
  mobx.makeObservable(this, {
739
+ resetValidatedOnce: mobx.action,
740
+ _validatedOnce: mobx.observable,
741
+ validatedAtLeastOnce: mobx.computed,
715
742
  _disabled: mobx.observable,
716
743
  _required: mobx.observable,
717
744
  waitForBlur: mobx.computed,
@@ -722,8 +749,10 @@ var Field = /*#__PURE__*/function () {
722
749
  hasValue: mobx.computed,
723
750
  _autoValidate: mobx.observable,
724
751
  _value: mobx.observable,
752
+ _initialValue: mobx.observable,
725
753
  _interacted: mobx.observable,
726
754
  _blurredOnce: mobx.observable,
755
+ dirty: mobx.computed,
727
756
  blurred: mobx.computed,
728
757
  errorMessage: mobx.computed,
729
758
  rawError: mobx.observable.ref,
@@ -811,15 +840,22 @@ var FormModel = /*#__PURE__*/function () {
811
840
  return field.restoreInitialValue(opts);
812
841
  });
813
842
  }
843
+ }, {
844
+ key: "commit",
845
+ value: function commit() {
846
+ this._eachField(function (field) {
847
+ return field.commit();
848
+ });
849
+ }
850
+ }, {
851
+ key: "updateFrom",
852
+
814
853
  /**
815
854
  * Set multiple values to more than one field a time using an object
816
855
  * where each key is the name of a field. The value will be set to each
817
856
  * field and from that point on the values set are considered the new
818
857
  * initial values. Validation and interacted flags are also reset if the second argument is true
819
858
  * */
820
-
821
- }, {
822
- key: "updateFrom",
823
859
  value: function updateFrom(obj) {
824
860
  var _this = this;
825
861
 
@@ -884,6 +920,16 @@ var FormModel = /*#__PURE__*/function () {
884
920
  * return the data as plain Javascript object (mobx magic removed from the fields)
885
921
  * */
886
922
 
923
+ }, {
924
+ key: "validatedAtLeastOnce",
925
+ get: function get() {
926
+ var _this3 = this;
927
+
928
+ var keys = Object.keys(this.fields);
929
+ return keys.every(function (key) {
930
+ return _this3.fields[key].validatedAtLeastOnce;
931
+ });
932
+ }
887
933
  }, {
888
934
  key: "dataIsReady",
889
935
  get: function get() {
@@ -892,21 +938,21 @@ var FormModel = /*#__PURE__*/function () {
892
938
  }, {
893
939
  key: "requiredFields",
894
940
  get: function get() {
895
- var _this3 = this;
941
+ var _this4 = this;
896
942
 
897
943
  var keys = Object.keys(this.fields);
898
944
  return keys.filter(function (key) {
899
- return _this3.fields[key].required;
945
+ return _this4.fields[key].required;
900
946
  });
901
947
  }
902
948
  }, {
903
949
  key: "requiredAreFilled",
904
950
  get: function get() {
905
- var _this4 = this;
951
+ var _this5 = this;
906
952
 
907
953
  var keys = Object.keys(this.fields);
908
954
  return keys.every(function (key) {
909
- var field = _this4.fields[key];
955
+ var field = _this5.fields[key];
910
956
 
911
957
  if (field.required) {
912
958
  return !!field.hasValue;
@@ -921,7 +967,7 @@ var FormModel = /*#__PURE__*/function () {
921
967
  // since some of the validators might be async validators
922
968
  // this value might be false until the validation process finish
923
969
  get: function get() {
924
- var _this5 = this;
970
+ var _this6 = this;
925
971
 
926
972
  if (this._validating) {
927
973
  return false; // consider the form invalid until the validation process finish
@@ -929,7 +975,7 @@ var FormModel = /*#__PURE__*/function () {
929
975
 
930
976
  var keys = Object.keys(this.fields);
931
977
  return keys.every(function (key) {
932
- var field = _this5.fields[key];
978
+ var field = _this6.fields[key];
933
979
  return !!field.valid;
934
980
  });
935
981
  }
@@ -942,22 +988,33 @@ var FormModel = /*#__PURE__*/function () {
942
988
  }, {
943
989
  key: "interacted",
944
990
  get: function get() {
945
- var _this6 = this;
991
+ var _this7 = this;
946
992
 
947
993
  var keys = this._fieldKeys();
948
994
 
949
995
  return keys.some(function (key) {
950
- var field = _this6.fields[key];
996
+ var field = _this7.fields[key];
951
997
  return !!field.interacted;
952
998
  });
953
999
  }
1000
+ }, {
1001
+ key: "dirty",
1002
+ get: function get() {
1003
+ var _this8 = this;
1004
+
1005
+ return this._fieldKeys().some(function (key) {
1006
+ var f = _this8._getField(key);
1007
+
1008
+ return f.dirty;
1009
+ });
1010
+ }
954
1011
  }, {
955
1012
  key: "summary",
956
1013
  get: function get() {
957
- var _this7 = this;
1014
+ var _this9 = this;
958
1015
 
959
1016
  return this._fieldKeys().reduce(function (seq, key) {
960
- var field = _this7.fields[key];
1017
+ var field = _this9.fields[key];
961
1018
 
962
1019
  if (field.errorMessage) {
963
1020
  seq.push(field.errorMessage);
@@ -969,10 +1026,10 @@ var FormModel = /*#__PURE__*/function () {
969
1026
  }, {
970
1027
  key: "validating",
971
1028
  get: function get() {
972
- var _this8 = this;
1029
+ var _this10 = this;
973
1030
 
974
1031
  return this._validating || this._fieldKeys().some(function (key) {
975
- var f = _this8._getField(key);
1032
+ var f = _this10._getField(key);
976
1033
 
977
1034
  return f.validating;
978
1035
  });
@@ -980,11 +1037,11 @@ var FormModel = /*#__PURE__*/function () {
980
1037
  }, {
981
1038
  key: "serializedData",
982
1039
  get: function get() {
983
- var _this9 = this;
1040
+ var _this11 = this;
984
1041
 
985
1042
  var keys = Object.keys(this.fields);
986
1043
  return mobx.toJS(keys.reduce(function (seq, key) {
987
- var field = _this9.fields[key];
1044
+ var field = _this11.fields[key];
988
1045
  var value = mobx.toJS(field.value); // this is required to make sure forms that use the serializedData object
989
1046
  // have the values without leading or trailing spaces
990
1047
 
@@ -1005,7 +1062,7 @@ var FormModel = /*#__PURE__*/function () {
1005
1062
  }]);
1006
1063
 
1007
1064
  function FormModel() {
1008
- var _this10 = this;
1065
+ var _this12 = this;
1009
1066
 
1010
1067
  var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
1011
1068
  _ref2$descriptors = _ref2.descriptors,
@@ -1020,7 +1077,7 @@ var FormModel = /*#__PURE__*/function () {
1020
1077
  this._validating = false;
1021
1078
 
1022
1079
  this.setValidating = function (validating) {
1023
- _this10._validating = validating;
1080
+ _this12._validating = validating;
1024
1081
  };
1025
1082
 
1026
1083
  this.addFields = function (fieldsDescriptor) {
@@ -1034,7 +1091,7 @@ var FormModel = /*#__PURE__*/function () {
1034
1091
  name = field.name,
1035
1092
  descriptor = _objectWithoutProperties(field, ["value", "name"]);
1036
1093
 
1037
- _this10._createField({
1094
+ _this12._createField({
1038
1095
  value: value,
1039
1096
  name: name,
1040
1097
  descriptor: descriptor
@@ -1049,7 +1106,7 @@ var FormModel = /*#__PURE__*/function () {
1049
1106
  value = _fieldsDescriptor$key.value,
1050
1107
  descriptor = _objectWithoutProperties(_fieldsDescriptor$key, ["value"]);
1051
1108
 
1052
- _this10._createField({
1109
+ _this12._createField({
1053
1110
  value: value,
1054
1111
  name: key,
1055
1112
  descriptor: descriptor
@@ -1058,6 +1115,8 @@ var FormModel = /*#__PURE__*/function () {
1058
1115
  };
1059
1116
 
1060
1117
  mobx.makeObservable(this, {
1118
+ resetValidatedOnce: mobx.action,
1119
+ validatedAtLeastOnce: mobx.computed,
1061
1120
  dataIsReady: mobx.computed,
1062
1121
  requiredFields: mobx.computed,
1063
1122
  requiredAreFilled: mobx.computed,
@@ -1076,11 +1135,14 @@ var FormModel = /*#__PURE__*/function () {
1076
1135
  resetInteractedFlag: mobx.action,
1077
1136
  disableFields: mobx.action,
1078
1137
  addFields: mobx.action,
1079
- enableFields: mobx.action
1138
+ enableFields: mobx.action,
1139
+ commit: mobx.action,
1140
+ dirty: mobx.computed
1080
1141
  });
1081
1142
  this.addFields(descriptors);
1082
1143
  initialState && this.updateFrom(initialState, {
1083
- throwIfMissingField: options.throwIfMissingField
1144
+ throwIfMissingField: options.throwIfMissingField,
1145
+ commit: true
1084
1146
  });
1085
1147
  }
1086
1148
 
@@ -1102,10 +1164,10 @@ var FormModel = /*#__PURE__*/function () {
1102
1164
  }, {
1103
1165
  key: "_eachField",
1104
1166
  value: function _eachField(cb) {
1105
- var _this11 = this;
1167
+ var _this13 = this;
1106
1168
 
1107
1169
  Object.keys(this.fields).forEach(function (key) {
1108
- return cb(_this11.fields[key]);
1170
+ return cb(_this13.fields[key]);
1109
1171
  });
1110
1172
  }
1111
1173
  }, {
@@ -1123,11 +1185,11 @@ var FormModel = /*#__PURE__*/function () {
1123
1185
  }, {
1124
1186
  key: "disableFields",
1125
1187
  value: function disableFields(fieldKeys) {
1126
- var _this12 = this;
1188
+ var _this14 = this;
1127
1189
 
1128
1190
  if (!Array.isArray(fieldKeys)) throw new TypeError('fieldKeys should be an array with the names of the fields to disable');
1129
1191
  fieldKeys.forEach(function (key) {
1130
- var field = _this12._getField(key);
1192
+ var field = _this14._getField(key);
1131
1193
 
1132
1194
  field.setDisabled(true);
1133
1195
  });
@@ -1143,15 +1205,24 @@ var FormModel = /*#__PURE__*/function () {
1143
1205
  }, {
1144
1206
  key: "enableFields",
1145
1207
  value: function enableFields(fieldKeys) {
1146
- var _this13 = this;
1208
+ var _this15 = this;
1147
1209
 
1148
1210
  if (!Array.isArray(fieldKeys)) throw new TypeError('fieldKeys should be an array with the names of the fields to disable');
1149
1211
  fieldKeys.forEach(function (key) {
1150
- var field = _this13._getField(key);
1212
+ var field = _this15._getField(key);
1151
1213
 
1152
1214
  field.setDisabled(false);
1153
1215
  });
1154
1216
  }
1217
+ }, {
1218
+ key: "resetValidatedOnce",
1219
+ value: function resetValidatedOnce() {
1220
+ var _this16 = this;
1221
+
1222
+ this._fieldKeys().forEach(function (key) {
1223
+ _this16.fields[key].resetValidatedOnce();
1224
+ });
1225
+ }
1155
1226
  }]);
1156
1227
 
1157
1228
  return FormModel;
@@ -263,6 +263,11 @@
263
263
  value: function markAsInteracted() {
264
264
  this._interacted = true;
265
265
  }
266
+ }, {
267
+ key: "resetValidatedOnce",
268
+ value: function resetValidatedOnce() {
269
+ this._validatedOnce = false;
270
+ }
266
271
  }, {
267
272
  key: "_setValueOnly",
268
273
  value: function _setValueOnly(val) {
@@ -332,10 +337,13 @@
332
337
  value: function restoreInitialValue() {
333
338
  var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
334
339
  _ref2$resetInteracted = _ref2.resetInteractedFlag,
335
- resetInteractedFlag = _ref2$resetInteracted === void 0 ? true : _ref2$resetInteracted;
340
+ resetInteractedFlag = _ref2$resetInteracted === void 0 ? true : _ref2$resetInteracted,
341
+ _ref2$commit = _ref2.commit,
342
+ commit = _ref2$commit === void 0 ? true : _ref2$commit;
336
343
 
337
344
  this.setValue(this._initialValue, {
338
- resetInteractedFlag: resetInteractedFlag
345
+ resetInteractedFlag: resetInteractedFlag,
346
+ commit: commit
339
347
  });
340
348
  }
341
349
  }, {
@@ -494,6 +502,11 @@
494
502
  force = _ref3$force === void 0 ? false : _ref3$force;
495
503
 
496
504
  var required = this.required;
505
+
506
+ if (!this._validatedOnce) {
507
+ this._validatedOnce = true;
508
+ }
509
+
497
510
  var shouldSkipValidation = this.disabled || !required && !this._validateFn;
498
511
  if (shouldSkipValidation) return;
499
512
 
@@ -611,6 +624,11 @@
611
624
  value: function setError(error) {
612
625
  this.rawError = error;
613
626
  }
627
+ }, {
628
+ key: "validatedAtLeastOnce",
629
+ get: function get() {
630
+ return this._validatedOnce;
631
+ }
614
632
  }, {
615
633
  key: "waitForBlur",
616
634
  get: function get() {
@@ -713,6 +731,11 @@
713
731
  set: function set(val) {
714
732
  this._setValue(val);
715
733
  }
734
+ }, {
735
+ key: "dirty",
736
+ get: function get() {
737
+ return this._initialValue !== this.value;
738
+ }
716
739
  }, {
717
740
  key: "originalErrorMessage",
718
741
  get: function get() {
@@ -740,6 +763,7 @@
740
763
 
741
764
  this._disabled = void 0;
742
765
  this._required = void 0;
766
+ this._validatedOnce = false;
743
767
  this._validating = false;
744
768
  this._initialValue = void 0;
745
769
  this._value = void 0;
@@ -772,6 +796,9 @@
772
796
  };
773
797
 
774
798
  mobx.makeObservable(this, {
799
+ resetValidatedOnce: mobx.action,
800
+ _validatedOnce: mobx.observable,
801
+ validatedAtLeastOnce: mobx.computed,
775
802
  _disabled: mobx.observable,
776
803
  _required: mobx.observable,
777
804
  waitForBlur: mobx.computed,
@@ -782,8 +809,10 @@
782
809
  hasValue: mobx.computed,
783
810
  _autoValidate: mobx.observable,
784
811
  _value: mobx.observable,
812
+ _initialValue: mobx.observable,
785
813
  _interacted: mobx.observable,
786
814
  _blurredOnce: mobx.observable,
815
+ dirty: mobx.computed,
787
816
  blurred: mobx.computed,
788
817
  errorMessage: mobx.computed,
789
818
  rawError: mobx.observable.ref,
@@ -871,15 +900,22 @@
871
900
  return field.restoreInitialValue(opts);
872
901
  });
873
902
  }
903
+ }, {
904
+ key: "commit",
905
+ value: function commit() {
906
+ this._eachField(function (field) {
907
+ return field.commit();
908
+ });
909
+ }
910
+ }, {
911
+ key: "updateFrom",
912
+
874
913
  /**
875
914
  * Set multiple values to more than one field a time using an object
876
915
  * where each key is the name of a field. The value will be set to each
877
916
  * field and from that point on the values set are considered the new
878
917
  * initial values. Validation and interacted flags are also reset if the second argument is true
879
918
  * */
880
-
881
- }, {
882
- key: "updateFrom",
883
919
  value: function updateFrom(obj) {
884
920
  var _this = this;
885
921
 
@@ -944,6 +980,16 @@
944
980
  * return the data as plain Javascript object (mobx magic removed from the fields)
945
981
  * */
946
982
 
983
+ }, {
984
+ key: "validatedAtLeastOnce",
985
+ get: function get() {
986
+ var _this3 = this;
987
+
988
+ var keys = Object.keys(this.fields);
989
+ return keys.every(function (key) {
990
+ return _this3.fields[key].validatedAtLeastOnce;
991
+ });
992
+ }
947
993
  }, {
948
994
  key: "dataIsReady",
949
995
  get: function get() {
@@ -952,21 +998,21 @@
952
998
  }, {
953
999
  key: "requiredFields",
954
1000
  get: function get() {
955
- var _this3 = this;
1001
+ var _this4 = this;
956
1002
 
957
1003
  var keys = Object.keys(this.fields);
958
1004
  return keys.filter(function (key) {
959
- return _this3.fields[key].required;
1005
+ return _this4.fields[key].required;
960
1006
  });
961
1007
  }
962
1008
  }, {
963
1009
  key: "requiredAreFilled",
964
1010
  get: function get() {
965
- var _this4 = this;
1011
+ var _this5 = this;
966
1012
 
967
1013
  var keys = Object.keys(this.fields);
968
1014
  return keys.every(function (key) {
969
- var field = _this4.fields[key];
1015
+ var field = _this5.fields[key];
970
1016
 
971
1017
  if (field.required) {
972
1018
  return !!field.hasValue;
@@ -981,7 +1027,7 @@
981
1027
  // since some of the validators might be async validators
982
1028
  // this value might be false until the validation process finish
983
1029
  get: function get() {
984
- var _this5 = this;
1030
+ var _this6 = this;
985
1031
 
986
1032
  if (this._validating) {
987
1033
  return false; // consider the form invalid until the validation process finish
@@ -989,7 +1035,7 @@
989
1035
 
990
1036
  var keys = Object.keys(this.fields);
991
1037
  return keys.every(function (key) {
992
- var field = _this5.fields[key];
1038
+ var field = _this6.fields[key];
993
1039
  return !!field.valid;
994
1040
  });
995
1041
  }
@@ -1002,22 +1048,33 @@
1002
1048
  }, {
1003
1049
  key: "interacted",
1004
1050
  get: function get() {
1005
- var _this6 = this;
1051
+ var _this7 = this;
1006
1052
 
1007
1053
  var keys = this._fieldKeys();
1008
1054
 
1009
1055
  return keys.some(function (key) {
1010
- var field = _this6.fields[key];
1056
+ var field = _this7.fields[key];
1011
1057
  return !!field.interacted;
1012
1058
  });
1013
1059
  }
1060
+ }, {
1061
+ key: "dirty",
1062
+ get: function get() {
1063
+ var _this8 = this;
1064
+
1065
+ return this._fieldKeys().some(function (key) {
1066
+ var f = _this8._getField(key);
1067
+
1068
+ return f.dirty;
1069
+ });
1070
+ }
1014
1071
  }, {
1015
1072
  key: "summary",
1016
1073
  get: function get() {
1017
- var _this7 = this;
1074
+ var _this9 = this;
1018
1075
 
1019
1076
  return this._fieldKeys().reduce(function (seq, key) {
1020
- var field = _this7.fields[key];
1077
+ var field = _this9.fields[key];
1021
1078
 
1022
1079
  if (field.errorMessage) {
1023
1080
  seq.push(field.errorMessage);
@@ -1029,10 +1086,10 @@
1029
1086
  }, {
1030
1087
  key: "validating",
1031
1088
  get: function get() {
1032
- var _this8 = this;
1089
+ var _this10 = this;
1033
1090
 
1034
1091
  return this._validating || this._fieldKeys().some(function (key) {
1035
- var f = _this8._getField(key);
1092
+ var f = _this10._getField(key);
1036
1093
 
1037
1094
  return f.validating;
1038
1095
  });
@@ -1040,11 +1097,11 @@
1040
1097
  }, {
1041
1098
  key: "serializedData",
1042
1099
  get: function get() {
1043
- var _this9 = this;
1100
+ var _this11 = this;
1044
1101
 
1045
1102
  var keys = Object.keys(this.fields);
1046
1103
  return mobx.toJS(keys.reduce(function (seq, key) {
1047
- var field = _this9.fields[key];
1104
+ var field = _this11.fields[key];
1048
1105
  var value = mobx.toJS(field.value); // this is required to make sure forms that use the serializedData object
1049
1106
  // have the values without leading or trailing spaces
1050
1107
 
@@ -1065,7 +1122,7 @@
1065
1122
  }]);
1066
1123
 
1067
1124
  function FormModel() {
1068
- var _this10 = this;
1125
+ var _this12 = this;
1069
1126
 
1070
1127
  var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
1071
1128
  _ref2$descriptors = _ref2.descriptors,
@@ -1080,7 +1137,7 @@
1080
1137
  this._validating = false;
1081
1138
 
1082
1139
  this.setValidating = function (validating) {
1083
- _this10._validating = validating;
1140
+ _this12._validating = validating;
1084
1141
  };
1085
1142
 
1086
1143
  this.addFields = function (fieldsDescriptor) {
@@ -1094,7 +1151,7 @@
1094
1151
  name = field.name,
1095
1152
  descriptor = _objectWithoutProperties(field, ["value", "name"]);
1096
1153
 
1097
- _this10._createField({
1154
+ _this12._createField({
1098
1155
  value: value,
1099
1156
  name: name,
1100
1157
  descriptor: descriptor
@@ -1109,7 +1166,7 @@
1109
1166
  value = _fieldsDescriptor$key.value,
1110
1167
  descriptor = _objectWithoutProperties(_fieldsDescriptor$key, ["value"]);
1111
1168
 
1112
- _this10._createField({
1169
+ _this12._createField({
1113
1170
  value: value,
1114
1171
  name: key,
1115
1172
  descriptor: descriptor
@@ -1118,6 +1175,8 @@
1118
1175
  };
1119
1176
 
1120
1177
  mobx.makeObservable(this, {
1178
+ resetValidatedOnce: mobx.action,
1179
+ validatedAtLeastOnce: mobx.computed,
1121
1180
  dataIsReady: mobx.computed,
1122
1181
  requiredFields: mobx.computed,
1123
1182
  requiredAreFilled: mobx.computed,
@@ -1136,11 +1195,14 @@
1136
1195
  resetInteractedFlag: mobx.action,
1137
1196
  disableFields: mobx.action,
1138
1197
  addFields: mobx.action,
1139
- enableFields: mobx.action
1198
+ enableFields: mobx.action,
1199
+ commit: mobx.action,
1200
+ dirty: mobx.computed
1140
1201
  });
1141
1202
  this.addFields(descriptors);
1142
1203
  initialState && this.updateFrom(initialState, {
1143
- throwIfMissingField: options.throwIfMissingField
1204
+ throwIfMissingField: options.throwIfMissingField,
1205
+ commit: true
1144
1206
  });
1145
1207
  }
1146
1208
 
@@ -1162,10 +1224,10 @@
1162
1224
  }, {
1163
1225
  key: "_eachField",
1164
1226
  value: function _eachField(cb) {
1165
- var _this11 = this;
1227
+ var _this13 = this;
1166
1228
 
1167
1229
  Object.keys(this.fields).forEach(function (key) {
1168
- return cb(_this11.fields[key]);
1230
+ return cb(_this13.fields[key]);
1169
1231
  });
1170
1232
  }
1171
1233
  }, {
@@ -1183,11 +1245,11 @@
1183
1245
  }, {
1184
1246
  key: "disableFields",
1185
1247
  value: function disableFields(fieldKeys) {
1186
- var _this12 = this;
1248
+ var _this14 = this;
1187
1249
 
1188
1250
  if (!Array.isArray(fieldKeys)) throw new TypeError('fieldKeys should be an array with the names of the fields to disable');
1189
1251
  fieldKeys.forEach(function (key) {
1190
- var field = _this12._getField(key);
1252
+ var field = _this14._getField(key);
1191
1253
 
1192
1254
  field.setDisabled(true);
1193
1255
  });
@@ -1203,15 +1265,24 @@
1203
1265
  }, {
1204
1266
  key: "enableFields",
1205
1267
  value: function enableFields(fieldKeys) {
1206
- var _this13 = this;
1268
+ var _this15 = this;
1207
1269
 
1208
1270
  if (!Array.isArray(fieldKeys)) throw new TypeError('fieldKeys should be an array with the names of the fields to disable');
1209
1271
  fieldKeys.forEach(function (key) {
1210
- var field = _this13._getField(key);
1272
+ var field = _this15._getField(key);
1211
1273
 
1212
1274
  field.setDisabled(false);
1213
1275
  });
1214
1276
  }
1277
+ }, {
1278
+ key: "resetValidatedOnce",
1279
+ value: function resetValidatedOnce() {
1280
+ var _this16 = this;
1281
+
1282
+ this._fieldKeys().forEach(function (key) {
1283
+ _this16.fields[key].resetValidatedOnce();
1284
+ });
1285
+ }
1215
1286
  }]);
1216
1287
 
1217
1288
  return FormModel;
package/mobx-form.d.ts CHANGED
@@ -62,6 +62,11 @@ declare module 'mobx-form' {
62
62
  }
63
63
 
64
64
  export interface IField<T, K> {
65
+
66
+ validatedAtLeastOnce: boolean;
67
+
68
+ resetValidatedOnce(): void;
69
+
65
70
  waitForBlur: boolean;
66
71
 
67
72
  disabled: boolean;
@@ -112,11 +117,15 @@ declare module 'mobx-form' {
112
117
  }
113
118
 
114
119
  export interface IFormModel<T> {
120
+ validatedAtLeastOnce: boolean;
121
+
115
122
  dataIsReady: boolean;
116
123
 
117
124
  requiredFields: string[];
118
125
 
119
126
  requiredAreFilled: boolean;
127
+
128
+ resetValidatedOnce(): void;
120
129
 
121
130
  fields: {
122
131
  [P in keyof T]: IField<T[P], T>;
@@ -128,11 +137,15 @@ declare module 'mobx-form' {
128
137
 
129
138
  interacted: boolean;
130
139
 
131
- restoreInitialValues(options?: ResetInteractedFlagType): void;
140
+ dirty: boolean;
141
+
142
+ commit(): void;
143
+
144
+ restoreInitialValues(options?: SetValueFnArgs): void;
132
145
 
133
146
  resetInteractedFlag(options?: ResetInteractedFlagType): void;
134
147
 
135
- updateFrom(obj: Partial<T>, options?: ResetInteractedFlagType): void;
148
+ updateFrom(obj: Partial<T>, options?: SetValueFnArgs): void;
136
149
 
137
150
  enableFields(fieldNames: string[]): void;
138
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobx-form",
3
- "version": "13.2.1",
3
+ "version": "13.3.1",
4
4
  "description": "A simple form helper for mobx",
5
5
  "main": "dist/mobx-form.cjs.js",
6
6
  "_browser": "dist/mobx-form.umd.js",