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

Commit b29b3ab

Browse files
committed
Merge branch 'master' of github.com:davidkpiano/react-redux-form
2 parents 98fa978 + 2183bf1 commit b29b3ab

13 files changed

+4689
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ examples/sandbox
4646

4747
# Other
4848
.vscode/
49+
.idea/

.travis.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@ language: node_js
33
node_js:
44
- "4.0"
55
- "4"
6+
- "7"
67
- "stable"
78

9+
# before_install:
10+
# - npm config set ignore-scripts true
11+
812
script:
9-
- npm test
13+
- yarn test
14+
- yarn run lint
15+
- yarn run build
16+
- yarn run tsdef
17+
18+
cache: yarn
19+
# cache:
20+
# directories:
21+
# - node_modules
1022

1123
branches:
1224
except:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"build:lib": "babel src --out-dir lib",
1818
"analyze": "webpack src/index.js dist/index.js --config webpack.config.prod.js --json > stats.json",
1919
"preversion": "npm run test && npm run lint",
20-
"prepublish": "npm test && npm run lint && npm run build && npm run tsdef",
20+
"prepublishOnly": "npm test && npm run lint && npm run build && npm run tsdef",
2121
"postversion": "git push && git push --tags",
2222
"publish:beta": "npm publish --tag beta",
2323
"tsdef": "cp -f immutable.d.ts lib/",

src/actions/model-actions.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ export function createModelActions(s = defaultStrategies) {
9696
return change(model, multiValue);
9797
}
9898

99-
return change(model, !currentValue);
99+
if (typeof value === 'undefined') {
100+
return change(model, !currentValue);
101+
}
102+
return change(model, value);
100103
};
101104

102105
const check = (model, value) => (dispatch, getState) => {

src/components/control-component.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import isNative from '../utils/is-native';
2828
import initialFieldState from '../constants/initial-field-state';
2929
import containsEvent from '../utils/contains-event';
3030

31+
import ComponentWrapper from './control-strip-defaults-component';
32+
3133
const findDOMNode = !isNative
3234
? require('react-dom').findDOMNode
3335
: null;
@@ -611,23 +613,29 @@ function createControlClass(s = defaultStrategy) {
611613
const mappedProps = omit(this.getMappedProps(), disallowedProps);
612614

613615
if (getRef) {
614-
mappedProps.ref = getRef;
616+
mappedProps.getRef = getRef;
615617
}
616618

617619
// If there is an existing control, clone it
618620
if (control) {
619621
return cloneElement(
620622
control,
621-
mappedProps,
622-
controlProps.children);
623+
{
624+
...mappedProps,
625+
defaultValue: undefined,
626+
defaultChecked: undefined,
627+
},
628+
controlProps.children
629+
);
623630
}
624-
625631
return createElement(
626-
component,
632+
ComponentWrapper,
627633
{
634+
component,
628635
...controlProps,
629636
...mappedProps,
630-
});
637+
}
638+
);
631639
}
632640
}
633641

@@ -665,23 +673,24 @@ function createControlClass(s = defaultStrategy) {
665673
const modelString = getModel(model, state);
666674
const fieldValue = s.getFieldFromState(state, modelString)
667675
|| initialFieldState;
676+
const modelValue = s.get(state, modelString);
668677

669678
return {
670679
model: modelString,
671-
modelValue: s.get(state, modelString),
680+
modelValue,
672681
fieldValue,
673682
controlProps: finalControlProps,
674683
};
675684
}
676685

677686
const ConnectedControl = resolveModel(connect(mapStateToProps, null, null, {
678-
areOwnPropsEqual(ownProps, nextOwnProps) {
679-
return shallowEqual(ownProps, nextOwnProps, {
687+
areOwnPropsEqual(nextOwnProps, ownProps) {
688+
return shallowEqual(nextOwnProps, ownProps, {
680689
omitKeys: ['mapProps'],
681690
});
682691
},
683-
areStatePropsEqual(stateProps, nextStateProps) {
684-
return shallowEqual(stateProps, nextStateProps, {
692+
areStatePropsEqual(nextStateProps, stateProps) {
693+
return shallowEqual(nextStateProps, stateProps, {
685694
deepKeys: ['controlProps'],
686695
});
687696
},
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
// Prevents the defaultValue/defaultChecked fields from rendering with value/checked
5+
class ComponentWrapper extends Component {
6+
render() {
7+
/* eslint-disable no-unused-vars */
8+
const {
9+
defaultValue,
10+
defaultChecked,
11+
component,
12+
getRef,
13+
...otherProps,
14+
} = this.props;
15+
/* eslint-enable */
16+
17+
if (getRef) {
18+
otherProps.ref = getRef;
19+
}
20+
const WrappedComponent = component;
21+
return <WrappedComponent {...otherProps} />;
22+
}
23+
}
24+
ComponentWrapper.propTypes = {
25+
component: PropTypes.any,
26+
defaultValue: PropTypes.any,
27+
defaultChecked: PropTypes.any,
28+
getRef: PropTypes.func,
29+
};
30+
export default ComponentWrapper;

src/constants/control-props-map.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ function isChecked(props) {
1717
return props.modelValue.some((item) =>
1818
item === props.value);
1919
}
20+
if (typeof props.modelValue === 'undefined') {
21+
if (typeof props.defaultChecked !== 'undefined') {
22+
return props.defaultChecked;
23+
}
24+
}
2025

2126
return !!props.modelValue;
2227
}
@@ -57,9 +62,7 @@ const controlPropsMap = {
5762
},
5863
checkbox: {
5964
...standardPropsMap,
60-
checked: (props) => (props.defaultChecked
61-
? props.checked
62-
: isChecked(props)),
65+
checked: isChecked,
6366
},
6467
radio: {
6568
...standardPropsMap,

test/control-component-spec.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,12 +325,14 @@ Object.keys(testContexts).forEach((testKey) => {
325325
assert.equal(
326326
get(store.getState().test, 'single'),
327327
false, 'false');
328+
assert.equal(checkbox.checked, false);
328329

329330
TestUtils.Simulate.change(checkbox);
330331

331332
assert.equal(
332333
get(store.getState().test, 'single'),
333334
true, 'true');
335+
assert.equal(checkbox.checked, true);
334336
});
335337

336338
it('should check/uncheck the checkbox when model is externally changed', () => {
@@ -350,6 +352,114 @@ Object.keys(testContexts).forEach((testKey) => {
350352
});
351353
});
352354

355+
describe('with <Control.checkbox /> (single toggle, dynamic form, defaultChecked)', () => {
356+
const initialState = getInitialState({ single: true });
357+
const store = testCreateStore({
358+
testForm: formReducer('test'),
359+
test: modelReducer('test', initialState),
360+
});
361+
362+
const field = TestUtils.renderIntoDocument(
363+
<Provider store={store}>
364+
<Control.checkbox model="test.other" defaultChecked />
365+
</Provider>
366+
);
367+
368+
const checkbox = TestUtils.findRenderedDOMComponentWithTag(field, 'input');
369+
370+
it('should initially set the checkbox to checked when defaultChecked is true', () => {
371+
assert.equal(checkbox.checked, true);
372+
});
373+
374+
it('should give each radio input a name attribute of the model', () => {
375+
assert.equal(checkbox.name, 'test.other');
376+
});
377+
378+
it('should dispatch a change event when changed', () => {
379+
TestUtils.Simulate.change(checkbox);
380+
381+
assert.equal(
382+
get(store.getState().test, 'other'),
383+
false, 'false');
384+
assert.equal(checkbox.checked, false);
385+
386+
TestUtils.Simulate.change(checkbox);
387+
388+
assert.equal(
389+
get(store.getState().test, 'other'),
390+
true, 'true');
391+
assert.equal(checkbox.checked, true);
392+
});
393+
394+
it('should check/uncheck the checkbox when model is externally changed', () => {
395+
store.dispatch(actions.change('test.other', true));
396+
assert.equal(checkbox.checked, true);
397+
398+
store.dispatch(actions.change('test.other', false));
399+
assert.equal(checkbox.checked, false);
400+
});
401+
402+
it('should uncheck the checkbox for any falsey value', () => {
403+
store.dispatch(actions.change('test.other', ''));
404+
405+
assert.equal(checkbox.checked, false);
406+
});
407+
});
408+
409+
describe('with <Control.checkbox /> (single toggle, dynamic form, !defaultChecked)', () => {
410+
const initialState = getInitialState({ single: true });
411+
const store = testCreateStore({
412+
testForm: formReducer('test'),
413+
test: modelReducer('test', initialState),
414+
});
415+
416+
const field = TestUtils.renderIntoDocument(
417+
<Provider store={store}>
418+
<Control.checkbox model="test.other" defaultChecked={false} />
419+
</Provider>
420+
);
421+
422+
const checkbox = TestUtils.findRenderedDOMComponentWithTag(field, 'input');
423+
424+
it('should initially set the checkbox to unchecked when defaultChecked is false', () => {
425+
assert.equal(checkbox.checked, false);
426+
});
427+
428+
it('should give each radio input a name attribute of the model', () => {
429+
assert.equal(checkbox.name, 'test.other');
430+
});
431+
432+
it('should dispatch a change event when changed', () => {
433+
TestUtils.Simulate.change(checkbox);
434+
435+
assert.equal(
436+
get(store.getState().test, 'other'),
437+
true, 'true');
438+
439+
TestUtils.Simulate.change(checkbox);
440+
441+
assert.equal(
442+
get(store.getState().test, 'other'),
443+
false, 'false');
444+
});
445+
446+
it('should check/uncheck the checkbox when model is externally changed', () => {
447+
store.dispatch(actions.change('test.other', false));
448+
449+
assert.equal(checkbox.checked, false);
450+
451+
store.dispatch(actions.change('test.other', true));
452+
453+
assert.equal(checkbox.checked, true);
454+
});
455+
456+
it('should uncheck the checkbox for any falsey value', () => {
457+
store.dispatch(actions.change('test.other', ''));
458+
459+
assert.equal(checkbox.checked, false);
460+
});
461+
});
462+
353463
describe('with <Control.checkbox /> (multi toggle)', () => {
354464
const initialState = getInitialState({ foo: [1] });
355465
const store = testCreateStore({

0 commit comments

Comments
 (0)