Skip to content

Commit

Permalink
Merge pull request #76 from smartprocure/fix/remove_array_errors
Browse files Browse the repository at this point in the history
FIX: Update errors correctly on array item remove
  • Loading branch information
stellarhoof authored Nov 22, 2024
2 parents 7c574ae + fbdc376 commit 7cbdfdf
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.14.3

- FIX: On removing an array item, corresponding errors must also be spliced.

# 0.14.2

- FIX: remove() removes all errors, not just the removed field.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mobx-autoform",
"version": "0.14.2",
"version": "0.14.3",
"description": "Ridiculously simple form state management with mobx",
"type": "module",
"main": "dist/cjs/index.js",
Expand Down
29 changes: 26 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ let defaultGetSnapshot = form => F.flattenObject(toJS(gatherFormValues(form)))

let defaultGetNestedSnapshot = form => F.unflattenObject(form.getSnapshot())

// Splice the form errors when a array item is removed
const spliceErrors = (errors, parentPath, nodePosition) => {
const parent = parentPath.join('.')
const parentLength = parentPath.length
const arrayErrors = pickByPrefixes([parent], errors)
const newErrors = omitByPrefixes([parent], errors)
for (const [key, value] of Object.entries(arrayErrors)) {
const keyFields = key.split('.')
const idx = parseInt(keyFields[parentLength])
if (idx > nodePosition) {
keyFields.splice(parentLength, 1, idx - 1)
const newKey = keyFields.join('.')
newErrors[newKey] = value
} else if (idx < nodePosition) {
newErrors[key] = value
}
}
return newErrors
}

export default ({
submit: configSubmit,
value = {},
Expand Down Expand Up @@ -110,15 +130,18 @@ export default ({
remove() {
let parent = form.getField(_.dropRight(1, rootPath)) || form
// If array field, remove the value and the reaction will take care of the rest
if (parent[keys.itemField]) parent.value.splice(node.field, 1)
if (parent[keys.itemField]) {
parent.value.splice(node.field, 1)
state.errors = spliceErrors(state.errors, parent.path, node.field)
}
// Remove object field
else {
node.dispose()
F.unsetOn(node.field, parent.value)
F.unsetOn(node.field, parent[keys.fields])
// Clean errors for this field and all subfields
state.errors = omitByPrefixes([dotPath], state.errors, node.field)
}
// Clean errors for this field and all subfields
state.errors = omitByPrefixes([dotPath], state.errors)
},
})
node.path = rootPath
Expand Down
70 changes: 70 additions & 0 deletions src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,76 @@ describe('Methods and computeds', () => {
})
})

it('errors on remove array item', () => {
const value = {
location: {
'country.state': { zip: '07016' },
addresses: [
{ street: 'Meridian0', tenants: ['John00', 'John01', 'John02'] },
{ street: 'Meridian1', tenants: ['John1'] },
{ street: 'Meridian2', tenants: ['John20', 'John21', 'John22'] },
{ street: 'Meridian3', tenants: ['John30', 'John31'] },
],
},
}
const fields = {
location: {
fields: {
'country.state': {
label: 'Dotted field name',
fields: {
zip: {
validator: () => 'Invalid zip',
},
name: {},
},
},
addresses: {
label: 'Array field',
itemField: {
label: 'Item field is a record',
fields: {
street: {},
tenants: {
label: 'Array field',
itemField: {
label: 'Item field is a primitive',
validator: arg => `Invalid tenant ${arg}`,
},
},
},
},
},
},
},
}
form = Form({ fields, value })
form.validate()
expect(_.size(form.errors)).toBe(10)

const tenentKey = 'location.addresses.2.tenants.1'
expect(form.errors[tenentKey]).toBe('Invalid tenant John21')
form.getField(tenentKey).remove()
expect(form.errors['location.addresses.2.tenants.0']).toBe(
'Invalid tenant John20'
)
// tenants.2 has moved up to tenants.1
expect(form.getField(tenentKey).value).toBe('John22')
expect(form.errors['location.addresses.2.tenants.1']).toBe(
'Invalid tenant John22'
)
expect(form.errors['location.addresses.2.tenants.2']).toBeUndefined()

const addressKey = 'location.addresses.1'
form.getField(addressKey).remove()
// address.2 has moved up to address.1
expect(form.getField('location.addresses.1.tenants.0').value).toBe('John20')
expect(form.errors['location.addresses.2.tenants.1']).toBe(
'Invalid tenant John31'
)
expect(form.errors['location.addresses.2.tenants.2']).toBeUndefined()
})

describe('validate()', () => {
it('field', () => {
let name = form.getField('location.addresses.0.tenants.0')
Expand Down

0 comments on commit 7cbdfdf

Please sign in to comment.