Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit 9dccc92

Browse files
committed
Adding field diffing to form reducer to dissociate removed fields. Fixes #84
1 parent c79c8ff commit 9dccc92

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"react-redux": "^4.4.0",
6161
"redux": "^3.3.1",
6262
"redux-mock-store": "0.0.6",
63+
"redux-test-store": "^0.3.0",
6364
"redux-thunk": "^2.0.1",
6465
"should": "^8.2.2",
6566
"webpack": "^1.12.14"

src/reducers/form-reducer.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import isEqual from 'lodash/isEqual';
66
import isPlainObject from 'lodash/isPlainObject';
77
import mapValues from 'lodash/mapValues';
88
import toPath from 'lodash/toPath';
9+
import startsWith from 'lodash/startsWith';
910
import flatten from 'flat';
1011

1112
import actionTypes from '../action-types';
@@ -82,6 +83,24 @@ function formIsValid(formState) {
8283
&& every(formState.errors, error => !error);
8384
}
8485

86+
function removeDiff(state, newValue, localPath) {
87+
const localKeys = Object.keys(state.fields)
88+
.filter((fieldKey) => startsWith(fieldKey, localPath));
89+
90+
let finalState = state;
91+
92+
localKeys.forEach((localKey) => {
93+
if (!_get({ [localPath]: newValue }, localKey, false)) {
94+
finalState = icepick.updateIn(
95+
finalState,
96+
['fields'],
97+
(obj) => icepick.dissoc(obj, localKey));
98+
}
99+
});
100+
101+
return finalState;
102+
}
103+
85104
function createInitialFormState(model, initialState) {
86105
const formState = icepick.set(initialFormState,
87106
'model', model);
@@ -127,7 +146,18 @@ function _createFormReducer(model, initialState) {
127146
focus: true,
128147
});
129148

130-
case actionTypes.CHANGE:
149+
case actionTypes.CHANGE: {
150+
const setDirtyState = icepick.merge(state, {
151+
dirty: true,
152+
pristine: false,
153+
});
154+
155+
return removeDiff(setField(setDirtyState, localPath, {
156+
dirty: true,
157+
pristine: false,
158+
}), action.value, localPath);
159+
}
160+
131161
case actionTypes.SET_DIRTY: {
132162
const setDirtyState = icepick.merge(state, {
133163
dirty: true,

test/model-actions-spec.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,42 @@ describe('model actions', () => {
194194
});
195195
/* eslint-enable */
196196
});
197+
198+
describe('remove()', () => {
199+
it('should dissociate removed fields from the form state', (done) => {
200+
const initialState = { items: [1, 2, 3] };
201+
const reducer = formReducer('test', initialState);
202+
203+
assert.property(reducer(undefined, { type: '' }).fields, 'items.2');
204+
205+
const dispatch = action => {
206+
assert.notProperty(reducer(undefined, action).fields, 'items.2');
207+
done();
208+
};
209+
210+
const getState = () => ({ test: initialState });
211+
212+
actions.remove('test.items', 2)(dispatch, getState);
213+
});
214+
});
215+
216+
describe('filter()', () => {
217+
it('should dissociate filtered fields from the form state', (done) => {
218+
const initialState = { items: [1, 2, 3, 4, 5] };
219+
const reducer = formReducer('test', initialState);
220+
221+
assert.property(reducer(undefined, { type: '' }).fields, 'items.3');
222+
assert.property(reducer(undefined, { type: '' }).fields, 'items.4');
223+
224+
const dispatch = action => {
225+
assert.notProperty(reducer(undefined, action).fields, 'items.3');
226+
assert.notProperty(reducer(undefined, action).fields, 'items.4');
227+
done();
228+
};
229+
230+
const getState = () => ({ test: initialState });
231+
232+
actions.filter('test.items', (n) => n % 2)(dispatch, getState);
233+
});
234+
});
197235
});

0 commit comments

Comments
 (0)