Skip to content

Commit 8a2ad42

Browse files
authored
Renamed merge to concat and fixed removeBatch bugs (#30)
1 parent b197a58 commit 8a2ad42

11 files changed

+296
-43
lines changed

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ const customer = form.mutators.pop('customers')
4949
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
5050

5151
- [Mutators](#mutators)
52+
- [`form.mutators.concat(name: string, value: Array<any>) => void`](#formmutatorsconcatname-string-value-arrayany--void)
5253
- [`form.mutators.insert(name: string, index: number, value: any) => undefined`](#formmutatorsinsertname-string-index-number-value-any--undefined)
53-
- [`form.mutators.merge(name: string, value: Array<any>) => void`](#formmutatorsmergename-string-value-arrayany--void)
5454
- [`form.mutators.move(name: string, from: number, to: number) => undefined`](#formmutatorsmovename-string-from-number-to-number--undefined)
5555
- [`form.mutators.pop(name: string) => any`](#formmutatorspopname-string--any)
5656
- [`form.mutators.push(name: string, value: any) => void`](#formmutatorspushname-string-value-any--void)
@@ -65,13 +65,13 @@ const customer = form.mutators.pop('customers')
6565

6666
## Mutators
6767

68-
### `form.mutators.insert(name: string, index: number, value: any) => undefined`
68+
### `form.mutators.concat(name: string, value: Array<any>) => void`
6969

70-
Inserts a value into the specified index of the array field.
70+
Concatenates an array at the end of the array field.
7171

72-
### `form.mutators.merge(name: string, value: Array<any>) => void`
72+
### `form.mutators.insert(name: string, index: number, value: any) => undefined`
7373

74-
Merges an array at the end of the array field.
74+
Inserts a value into the specified index of the array field.
7575

7676
### `form.mutators.move(name: string, from: number, to: number) => undefined`
7777

src/merge.js src/concat.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22
import type { MutableState, Mutator, Tools } from 'final-form'
33

4-
const merge: Mutator = (
4+
const concat: Mutator = (
55
[name, value]: any[],
66
state: MutableState,
77
{ changeValue }: Tools
@@ -13,4 +13,4 @@ const merge: Mutator = (
1313
)
1414
}
1515

16-
export default merge
16+
export default concat

src/merge.test.js src/concat.test.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import merge from './merge'
1+
import concat from './concat'
22

3-
describe('merge', () => {
3+
describe('concat', () => {
44
const getOp = value => {
55
const changeValue = jest.fn()
6-
merge(['foo', value], {}, { changeValue })
6+
concat(['foo', value], {}, { changeValue })
77
return changeValue.mock.calls[0][2]
88
}
99

1010
it('should call changeValue once', () => {
1111
const changeValue = jest.fn()
1212
const state = {}
13-
const result = merge(['foo', ['bar', 'baz']], state, { changeValue })
13+
const result = concat(['foo', ['bar', 'baz']], state, { changeValue })
1414
expect(result).toBeUndefined()
1515
expect(changeValue).toHaveBeenCalled()
1616
expect(changeValue).toHaveBeenCalledTimes(1)
@@ -26,7 +26,7 @@ describe('merge', () => {
2626
expect(result).toEqual(['bar', 'baz'])
2727
})
2828

29-
it('should merge the array at the end of the original array', () => {
29+
it('should concat the array at the end of the original array', () => {
3030
const op = getOp(['d', 'e'])
3131
const result = op(['a', 'b', 'c'])
3232
expect(Array.isArray(result)).toBe(true)

src/index.d.test.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ const form = createForm({
1515
const mutators: Mutators = (form.mutators as any) as Mutators
1616

1717
mutators.insert('customers', 0, { firstName: '', lastName: '' })
18-
mutators.merge('customers', [{ firstName: '', lastName: '' }, { firstName: '', lastName: '' }])
18+
mutators.concat('customers', [
19+
{ firstName: '', lastName: '' },
20+
{ firstName: '', lastName: '' }
21+
])
1922
mutators.move('customers', 0, 1)
2023
const customer = mutators.pop('customers')
2124
mutators.push('customers', { firstName: '', lastName: '' })

src/index.d.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Mutator } from 'final-form'
22

33
export const insert: Mutator
4-
export const merge: Mutator
4+
export const concat: Mutator
55
export const move: Mutator
66
export const pop: Mutator
77
export const push: Mutator
@@ -14,7 +14,7 @@ export const unshift: Mutator
1414

1515
export interface DefaultType {
1616
insert: Mutator
17-
merge: Mutator
17+
concat: Mutator
1818
move: Mutator
1919
pop: Mutator
2020
push: Mutator
@@ -32,7 +32,7 @@ export default d
3232
/** The shape of the mutators once final-form has bound them to state */
3333
export interface Mutators {
3434
insert: (name: string, index: number, value: any) => void
35-
merge: (name: string, value: Array<any>) => void,
35+
concat: (name: string, value: Array<any>) => void
3636
move: (name: string, from: number, to: number) => void
3737
pop: (name: string) => any
3838
push: (name: string, value: any) => void

src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22
import type { Mutator } from 'final-form'
33
import insert from './insert'
4-
import merge from './merge'
4+
import concat from './concat'
55
import move from './move'
66
import pop from './pop'
77
import push from './push'
@@ -14,7 +14,7 @@ import update from './update'
1414

1515
const mutators: { [string]: Mutator } = {
1616
insert,
17-
merge,
17+
concat,
1818
move,
1919
pop,
2020
push,

src/index.js.flow

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ declare export default DefaultType
88
/** The shape of the mutators once final-form has bound them to state */
99
export type Mutators = {
1010
insert: (name: string, index: number, value: any) => void,
11-
merge: (name: string, value: Array<any>) => void,
11+
concat: (name: string, value: Array<any>) => void,
1212
move: (name: string, from: number, to: number) => void,
1313
pop: (name: string) => any,
1414
push: (name: string, value: any) => void,

src/insert.test.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ describe('insert', () => {
3232
const state = {
3333
formState: {
3434
values: {
35-
foo: ['one', 'two']
35+
foo: ['one', 'two'],
36+
anotherField: 42
3637
}
3738
},
3839
fields: {
@@ -43,8 +44,11 @@ describe('insert', () => {
4344
},
4445
'foo[1]': {
4546
name: 'foo[1]',
46-
touched: false,
47-
error: 'Second Error'
47+
touched: false
48+
},
49+
anotherField: {
50+
name: 'anotherField',
51+
touched: true
4852
}
4953
}
5054
}

src/remove.test.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ describe('remove', () => {
6161
const state = {
6262
formState: {
6363
values: {
64-
foo: array
64+
foo: array,
65+
anotherField: 42
6566
}
6667
},
6768
fields: {
@@ -84,6 +85,10 @@ describe('remove', () => {
8485
name: 'foo[3]',
8586
touched: false,
8687
error: 'D Error'
88+
},
89+
anotherField: {
90+
name: 'anotherField',
91+
touched: false
8792
}
8893
}
8994
}
@@ -93,7 +98,8 @@ describe('remove', () => {
9398
expect(state).toEqual({
9499
formState: {
95100
values: {
96-
foo: ['a', 'c', 'd']
101+
foo: ['a', 'c', 'd'],
102+
anotherField: 42
97103
}
98104
},
99105
fields: {
@@ -111,6 +117,10 @@ describe('remove', () => {
111117
name: 'foo[2]',
112118
touched: false,
113119
error: 'D Error'
120+
},
121+
anotherField: {
122+
name: 'anotherField',
123+
touched: false
114124
}
115125
}
116126
})

src/removeBatch.js

+45-15
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,66 @@
11
// @flow
22
import type { MutableState, Mutator, Tools } from 'final-form'
33

4+
const countBelow = (array, value) =>
5+
array.reduce((count, item) => (item < value ? count + 1 : count), 0)
6+
47
const removeBatch: Mutator = (
58
[name, indexes]: any[],
69
state: MutableState,
710
{ changeValue }: Tools
811
) => {
12+
const sortedIndexes: number[] = [...indexes]
13+
sortedIndexes.sort()
14+
// remove duplicates
15+
for (let i = 0; i < sortedIndexes.length; i++) {
16+
if (i > 0 && sortedIndexes[i] === sortedIndexes[i - 1]) {
17+
sortedIndexes.splice(i--, 1)
18+
}
19+
}
20+
21+
let returnValue = []
922
changeValue(
1023
state,
1124
name,
1225
(array: ?(any[])): ?(any[]) => {
13-
if (!array || !indexes) {
26+
// use original order of indexes for return value
27+
returnValue = indexes.map(index => array && array[index])
28+
if (!array || !sortedIndexes.length) {
1429
return array
1530
}
1631

17-
let mask = new Array(indexes.length)
18-
for (let i = 0; i < indexes.length; i++) {
19-
mask[indexes[i]] = true
20-
}
32+
const copy = [...array]
33+
const removed = []
34+
sortedIndexes.forEach((index: number) => {
35+
copy.splice(index - removed.length, 1)
36+
removed.push(array && array[index])
37+
})
38+
return copy
39+
}
40+
)
2141

22-
let offset = 0
23-
for (let i = 0; i < array.length; i++) {
24-
if (mask[i] === undefined) {
25-
array[offset] = array[i]
26-
offset++
27-
}
42+
// now we have to remove any subfields for our indexes,
43+
// and decrement all higher indexes.
44+
const pattern = new RegExp(`^${name}\\[(\\d+)\\](.*)`)
45+
const newFields = {}
46+
Object.keys(state.fields).forEach(key => {
47+
const tokens = pattern.exec(key)
48+
if (tokens) {
49+
const fieldIndex = Number(tokens[1])
50+
if (!~sortedIndexes.indexOf(fieldIndex)) {
51+
// not one of the removed indexes
52+
// shift all higher ones down
53+
const decrementedKey = `${name}[${fieldIndex -
54+
countBelow(sortedIndexes, fieldIndex)}]${tokens[2]}`
55+
newFields[decrementedKey] = state.fields[key]
56+
newFields[decrementedKey].name = decrementedKey
2857
}
29-
30-
array.length = offset
31-
return array
58+
} else {
59+
newFields[key] = state.fields[key]
3260
}
33-
)
61+
})
62+
state.fields = newFields
63+
return returnValue
3464
}
3565

3666
export default removeBatch

0 commit comments

Comments
 (0)