@homebound/form-state 2.22.2 → 2.22.3

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.
@@ -163,6 +163,8 @@ function newObjectState(config, parentState, parentListState, instance, key, may
163
163
  get changedValue() {
164
164
  const result = {};
165
165
  getFields(this).forEach((f) => {
166
+ if (f._computed)
167
+ return;
166
168
  if (f.dirty ||
167
169
  // If the caller used useFormState.ifUndefined to provide some default values, then those keys may not
168
170
  // look dirty, but if we're new we should include them anyway.
@@ -18,6 +18,8 @@ function newValueFieldState(parentCopy, parentInstance, parentState, key, rules,
18
18
  _readOnly: readOnly || false,
19
19
  _loading: false,
20
20
  _focused: false,
21
+ // Expose so computed can be skipped in changedValue
22
+ _computed: computed,
21
23
  _isIdKey: isIdKey,
22
24
  _isDeleteKey: isDeleteKey,
23
25
  _isReadOnlyKey: isReadOnlyKey,
@@ -54,6 +56,12 @@ function newValueFieldState(parentCopy, parentInstance, parentState, key, rules,
54
56
  },
55
57
  // For primitive fields, the changed value is just the value.
56
58
  get changedValue() {
59
+ // Usually if we see a field being unset, we set `parent[key] = null`, but if we're wrapping
60
+ // a mobx observable object, it might have changed to `undefined` without us being able to
61
+ // tell it to be `null` (and potentially break the type contract of `string | undefined`).
62
+ // So detect un-set-ness here and return `null`.
63
+ if (this.value === undefined && this.originalValue !== undefined)
64
+ return null;
57
65
  return this.value;
58
66
  },
59
67
  get valid() {
@@ -979,11 +979,7 @@ describe("formState", () => {
979
979
  it("can observe observable objects being mutated directly", () => {
980
980
  // Given a mobx class with a computed
981
981
  const instance = new ObservableObject();
982
- const formState = (0, objectField_1.createObjectState)({
983
- firstName: { type: "value" },
984
- lastName: { type: "value" },
985
- fullName: { type: "value", computed: true },
986
- }, instance);
982
+ const formState = (0, objectField_1.createObjectState)(authorWithFullName, instance);
987
983
  expect(formState.firstName.value).toEqual("first");
988
984
  expect(formState.fullName.value).toEqual("first last");
989
985
  // And we hook up reactivity to the computed
@@ -999,9 +995,11 @@ describe("formState", () => {
999
995
  expect(formState.fullName.value).toEqual("change last");
1000
996
  // And when the underlying mobx class has a field unset
1001
997
  instance.firstName = undefined;
1002
- // Then our fomr-state computed re-runs again
998
+ // Then our form-state computed re-runs again
1003
999
  expect(numCalcs).toBe(3);
1004
1000
  expect(formState.fullName.value).toEqual("undefined last");
1001
+ // And knows the field should be sent as null
1002
+ expect(formState.changedValue).toEqual({ firstName: null });
1005
1003
  });
1006
1004
  it("can set computeds that have setters", () => {
1007
1005
  const formState = (0, objectField_1.createObjectState)({
@@ -1086,6 +1084,18 @@ describe("formState", () => {
1086
1084
  // because this might trigger creating a throw-away entity
1087
1085
  expect(formState.changedValue).toEqual({ firstName: "f" });
1088
1086
  });
1087
+ it("changedValue skips computeds", () => {
1088
+ // Given a new author that calls full name
1089
+ const formState = (0, objectField_1.createObjectState)(authorWithFullName, new ObservableObject());
1090
+ expect(formState.fullName.value).toEqual("first last");
1091
+ // When the firstName changes
1092
+ formState.firstName.value = "First";
1093
+ // Then the fullName changes
1094
+ expect(formState.fullName.value).toBe("First last");
1095
+ expect(formState.fullName.dirty).toBe(true);
1096
+ // And we don't include it in the changedValue
1097
+ expect(formState.changedValue).toEqual({ firstName: "First" });
1098
+ });
1089
1099
  it("can return only changed list fields", () => {
1090
1100
  // Given an author with some books
1091
1101
  const formState = (0, objectField_1.createObjectState)(authorWithBooksConfig, {
@@ -1579,6 +1589,11 @@ const authorWithBooksConfig = configBuilders_1.f.config({
1579
1589
  function createAuthorInputState(input, maybeAutoSave) {
1580
1590
  return (0, objectField_1.createObjectState)(authorWithBooksConfig, input, { maybeAutoSave });
1581
1591
  }
1592
+ const authorWithFullName = {
1593
+ firstName: { type: "value" },
1594
+ lastName: { type: "value" },
1595
+ fullName: { type: "value", computed: true },
1596
+ };
1582
1597
  const authorWithAddressConfig = {
1583
1598
  id: { type: "value" },
1584
1599
  firstName: { type: "value" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/form-state",
3
- "version": "2.22.2",
3
+ "version": "2.22.3",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",