diff --git a/src/move.test.js b/src/move.test.js index 91044c2..397c4c4 100644 --- a/src/move.test.js +++ b/src/move.test.js @@ -507,18 +507,38 @@ describe('move', () => { const after = mutate(before) state.formState.values = setIn(state.formState.values, name, after) || {} } + function blur0() {} + function change0() {} + function focus0() {} + function blur1() {} + function change1() {} + function focus1() {} const state = { formState: { values: { - foo: [{ dog: 'apple dog', cat: 'apple cat', colors: [{ name: 'red'}, { name: 'blue'}], deep: { inside: { rock: 'black'}} }, - { dog: 'banana dog', mouse: 'mickey', deep: { inside: { axe: 'golden' }} }] + foo: [ + { + dog: 'apple dog', + cat: 'apple cat', + colors: [{ name: 'red' }, { name: 'blue' }], + deep: { inside: { rock: 'black' } } + }, + { + dog: 'banana dog', + mouse: 'mickey', + deep: { inside: { axe: 'golden' } } + } + ] } }, fields: { 'foo[0].dog': { name: 'foo[0].dog', touched: true, - error: 'Error A Dog' + error: 'Error A Dog', + blur: blur0, + change: change0, + focus: focus0 }, 'foo[0].cat': { name: 'foo[0].cat', @@ -548,21 +568,35 @@ describe('move', () => { 'foo[1].mouse': { name: 'foo[1].mouse', touched: true, - error: 'Error B Mickey' + error: 'Error B Mickey', + blur: blur1, + change: change1, + focus: focus1 }, 'foo[1].deep.inside.axe': { name: 'foo[1].deep.inside.axe', touched: true, error: 'Error B Deep Inside Axe Golden' - }, + } } } move(['foo', 0, 1], state, { changeValue }) expect(state).toMatchObject({ formState: { values: { - foo: [{ dog: 'banana dog', mouse: 'mickey', deep: { inside: { axe: 'golden' }} }, - { dog: 'apple dog', cat: 'apple cat', colors: [{ name: 'red'}, { name: 'blue'}], deep: { inside: { rock: 'black'}} }] + foo: [ + { + dog: 'banana dog', + mouse: 'mickey', + deep: { inside: { axe: 'golden' } } + }, + { + dog: 'apple dog', + cat: 'apple cat', + colors: [{ name: 'red' }, { name: 'blue' }], + deep: { inside: { rock: 'black' } } + } + ] } }, fields: { @@ -576,7 +610,10 @@ describe('move', () => { name: 'foo[0].mouse', touched: true, error: 'Error B Mickey', - lastFieldState: undefined + lastFieldState: undefined, + blur: blur1, + change: change1, + focus: focus1 }, 'foo[0].deep.inside.axe': { name: 'foo[0].deep.inside.axe', @@ -587,7 +624,10 @@ describe('move', () => { name: 'foo[1].dog', touched: true, error: 'Error A Dog', - lastFieldState: undefined + lastFieldState: undefined, + blur: blur0, + change: change0, + focus: focus0 }, 'foo[1].cat': { name: 'foo[1].cat', @@ -611,7 +651,7 @@ describe('move', () => { name: 'foo[1].deep.inside.rock', touched: true, error: 'Error A Deep Inside Rock Black' - }, + } } }) }) @@ -630,40 +670,44 @@ describe('move', () => { } }, fields: { - 'foo[0]': { + 'foo[0].abc': { name: 'foo[0]', touched: true, error: 'Error A', lastFieldState: 'anything', - change: () => 'foo[0]' + change: () => 'customerId0', + blur: () => 'foo[0].abc blur', + focus: () => 'foo[0].abc focus' }, 'foo[1]': { name: 'foo[1]', touched: true, error: 'Error B', lastFieldState: 'anything', - change: () => 'foo[1]' + change: () => 'customerId1' }, 'foo[2]': { name: 'foo[2]', touched: false, error: 'Error C', lastFieldState: 'anything', - change: () => 'foo[2]' + change: () => 'customerId2' }, 'foo[3]': { name: 'foo[3]', touched: false, error: 'Error D', lastFieldState: 'anything', - change: () => 'foo[3]' + change: () => 'customerId3' } } } move(['foo', 0, 2], state, { changeValue }) - expect(state.fields['foo[0]'].change()).toBe('foo[0]') - expect(state.fields['foo[1]'].change()).toBe('foo[1]') - expect(state.fields['foo[2]'].change()).toBe('foo[2]') - expect(state.fields['foo[3]'].change()).toBe('foo[3]') + expect(state.fields['foo[0]'].change()).toBe('customerId1') + expect(state.fields['foo[1]'].change()).toBe('customerId2') + expect(state.fields['foo[2].abc'].change()).toBe('customerId0') + expect(state.fields['foo[2].abc'].blur()).toBe('foo[0].abc blur') + expect(state.fields['foo[2].abc'].focus()).toBe('foo[0].abc focus') + expect(state.fields['foo[3]'].change()).toBe('customerId3') }) }) diff --git a/src/moveFieldState.js b/src/moveFieldState.js index c1219ea..7d3b473 100644 --- a/src/moveFieldState.js +++ b/src/moveFieldState.js @@ -4,29 +4,28 @@ import type { MutableState } from 'final-form' function moveFieldState( state: MutableState, source: Object, - destKey: string, - oldState: MutableState = state + destKey: string ) { delete state.fields[source.name] state.fields[destKey] = { ...source, name: destKey, - // prevent functions from being overwritten - // if the state.fields[destKey] does not exist, it will be created - // when that field gets registered, with its own change/blur/focus callbacks - change: oldState.fields[destKey] && oldState.fields[destKey].change, - blur: oldState.fields[destKey] && oldState.fields[destKey].blur, - focus: oldState.fields[destKey] && oldState.fields[destKey].focus, + // we want to preserve the source functions so they do not copy from the wrong state value + // ie if we are moving foo[0] from 0 to 1, foo[0].change should be correctly moved under foo[1].change + // if foo[0].change returned a specific hash statically we want foo[1].change to return the same hash not what foo[1].change previously returned + change: source.change, + blur: source.blur, + focus: source.focus, lastFieldState: undefined // clearing lastFieldState forces renotification } if (!state.fields[destKey].change) { - delete state.fields[destKey].change; + delete state.fields[destKey].change } if (!state.fields[destKey].blur) { - delete state.fields[destKey].blur; + delete state.fields[destKey].blur } if (!state.fields[destKey].focus) { - delete state.fields[destKey].focus; + delete state.fields[destKey].focus } } diff --git a/src/remove.js b/src/remove.js index 887c906..5531a2d 100644 --- a/src/remove.js +++ b/src/remove.js @@ -43,7 +43,7 @@ const remove: Mutator = ( delete state.fields[key] const decrementedKey = `${name}[${fieldIndex - 1}]${tokens[2]}` if (backup.fields[decrementedKey]) { - moveFieldState(state, backup.fields[key], decrementedKey, backup) + moveFieldState(state, backup.fields[key], decrementedKey) } else { // take care of setting the correct change, blur, focus, validators on new field renameField(state, key, decrementedKey) diff --git a/src/remove.test.js b/src/remove.test.js index e103d7d..b96fac5 100644 --- a/src/remove.test.js +++ b/src/remove.test.js @@ -137,18 +137,18 @@ describe('remove', () => { }, 'foo[1]': { name: 'foo[1]', - blur: blur1, - change: change1, - focus: focus1, + blur: blur2, + change: change2, + focus: focus2, touched: true, error: 'C Error', lastFieldState: undefined }, 'foo[2]': { name: 'foo[2]', - blur: blur2, - change: change2, - focus: focus2, + blur: blur3, + change: change3, + focus: focus3, touched: false, error: 'D Error', lastFieldState: undefined @@ -252,18 +252,18 @@ describe('remove', () => { }, 'foo[0][1]': { name: 'foo[0][1]', - blur: blur1, - change: change1, - focus: focus1, + blur: blur2, + change: change2, + focus: focus2, touched: true, error: 'C Error', lastFieldState: undefined }, 'foo[0][2]': { name: 'foo[0][2]', - blur: blur2, - change: change2, - focus: focus2, + blur: blur3, + change: change3, + focus: focus3, touched: false, error: 'D Error', lastFieldState: undefined diff --git a/src/removeBatch.js b/src/removeBatch.js index 8c2480e..4cccc21 100644 --- a/src/removeBatch.js +++ b/src/removeBatch.js @@ -50,7 +50,7 @@ const removeBatch: Mutator = ( // shift all higher ones down const decrementedKey = `${name}[${fieldIndex - countBelow(sortedIndexes, fieldIndex)}]${tokens[2]}` - moveFieldState(newState, state.fields[key], decrementedKey, state) + moveFieldState(newState, state.fields[key], decrementedKey) } } else { newState.fields[key] = state.fields[key] diff --git a/src/removeBatch.test.js b/src/removeBatch.test.js index 15f0c8d..93957c6 100644 --- a/src/removeBatch.test.js +++ b/src/removeBatch.test.js @@ -170,9 +170,9 @@ describe('removeBatch', () => { fields: { 'foo[0]': { name: 'foo[0]', - blur: blur0, - change: change0, - focus: focus0, + blur: blur1, + change: change1, + focus: focus1, touched: false, error: 'Second Error', lastFieldState: undefined @@ -307,18 +307,18 @@ describe('removeBatch', () => { }, 'foo[1]': { name: 'foo[1]', - blur: blur1, - change: change1, - focus: focus1, + blur: blur3, + change: change3, + focus: focus3, touched: false, error: 'D Error', lastFieldState: undefined }, 'foo[2]': { name: 'foo[2]', - blur: blur2, - change: change2, - focus: focus2, + blur: blur4, + change: change4, + focus: focus4, touched: true, error: 'E Error', lastFieldState: undefined @@ -432,18 +432,18 @@ describe('removeBatch', () => { }, 'foo[0][1]': { name: 'foo[0][1]', - blur: blur1, - change: change1, - focus: focus1, + blur: blur3, + change: change3, + focus: focus3, touched: false, error: 'D Error', lastFieldState: undefined }, 'foo[0][2]': { name: 'foo[0][2]', - blur: blur2, - change: change2, - focus: focus2, + blur: blur4, + change: change4, + focus: focus4, touched: true, error: 'E Error', lastFieldState: undefined diff --git a/src/swap.js b/src/swap.js index e51fe25..43413c6 100644 --- a/src/swap.js +++ b/src/swap.js @@ -1,8 +1,7 @@ // @flow import type { MutableState, Mutator, Tools } from 'final-form' -import moveFieldState from './moveFieldState' -import moveFields from './moveFields'; -import restoreFunctions from './restoreFunctions'; +import moveFields from './moveFields' +import restoreFunctions from './restoreFunctions' const TMP: string = 'tmp' diff --git a/src/swap.test.js b/src/swap.test.js index 013940a..34bab6a 100644 --- a/src/swap.test.js +++ b/src/swap.test.js @@ -324,9 +324,9 @@ describe('swap', () => { } } swap(['foo', 0, 2], state, { changeValue }) - expect(state.fields['foo[0]'].change()).toBe('foo[0]') + expect(state.fields['foo[0]'].change()).toBe('foo[2]') expect(state.fields['foo[1]'].change()).toBe('foo[1]') - expect(state.fields['foo[2]'].change()).toBe('foo[2]') + expect(state.fields['foo[2]'].change()).toBe('foo[0]') expect(state.fields['foo[3]'].change()).toBe('foo[3]') }) })