Skip to content

Commit

Permalink
call props.onChange on Form component mount to set any defaults in sc… (
Browse files Browse the repository at this point in the history
#1034)

* call props.onChange on Form component mount to set any defaults in schema

* move onChange to contructor and only fire if defaults have been set

* call onChange if schema and formData prop changes cause a default to be set
  • Loading branch information
llamamoray authored and glasserc committed Sep 27, 2018
1 parent 4a653fc commit 9813483
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 2 deletions.
2 changes: 1 addition & 1 deletion playground/samples/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = {
firstName: {
type: "string",
title: "First name",
default: "Chuck",
},
lastName: {
type: "string",
Expand Down Expand Up @@ -60,7 +61,6 @@ module.exports = {
},
},
formData: {
firstName: "Chuck",
lastName: "Norris",
age: 75,
bio: "Roundhouse kicking asses since 1940",
Expand Down
16 changes: 15 additions & 1 deletion src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
toIdSchema,
setState,
getDefaultRegistry,
deepEquals,
} from "../utils";
import validateFormData, { toErrorList } from "../validate";

Expand All @@ -25,10 +26,23 @@ export default class Form extends Component {
constructor(props) {
super(props);
this.state = this.getStateFromProps(props);
if (
this.props.onChange &&
!deepEquals(this.state.formData, this.props.formData)
) {
this.props.onChange(this.state);
}
}

componentWillReceiveProps(nextProps) {
this.setState(this.getStateFromProps(nextProps));
const nextState = this.getStateFromProps(nextProps);
this.setState(nextState);
if (
!deepEquals(nextState.formData, nextProps.formData) &&
this.props.onChange
) {
this.props.onChange(nextState);
}
}

getStateFromProps(props) {
Expand Down
140 changes: 140 additions & 0 deletions test/Form_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,64 @@ describe("Form", () => {
});
});

describe("on component creation", () => {
let comp;
let onChangeProp;
let formData;
let schema;

function createComponent() {
comp = renderIntoDocument(
<Form schema={schema} onChange={onChangeProp} formData={formData}>
<button type="submit">Submit</button>
<button type="submit">Another submit</button>
</Form>
);
}

beforeEach(() => {
onChangeProp = sinon.spy();
schema = {
type: "object",
title: "root object",
required: ["count"],
properties: {
count: {
type: "number",
default: 789,
},
},
};
});

describe("when props.formData does not equal the default values", () => {
beforeEach(() => {
formData = {
foo: 123,
};
createComponent();
});

it("should call props.onChange with current state", () => {
sinon.assert.calledOnce(onChangeProp);
sinon.assert.calledWith(onChangeProp, comp.state);
});
});

describe("when props.formData equals the default values", () => {
beforeEach(() => {
formData = {
count: 789,
};
createComponent();
});

it("should not call props.onChange", () => {
sinon.assert.notCalled(onChangeProp);
});
});
});

describe("Option idPrefix", function() {
it("should change the rendered ids", function() {
const schema = {
Expand Down Expand Up @@ -767,6 +825,88 @@ describe("Form", () => {
});
});

describe("Schema and external formData updates", () => {
let comp;
let onChangeProp;

beforeEach(() => {
onChangeProp = sinon.spy();
const formProps = {
schema: {
type: "string",
default: "foobar",
},
formData: "some value",
onChange: onChangeProp,
};
comp = createFormComponent(formProps).comp;
});

describe("when the form data is set to null", () => {
beforeEach(() => comp.componentWillReceiveProps({ formData: null }));

it("should call onChange", () => {
sinon.assert.calledOnce(onChangeProp);
sinon.assert.calledWith(onChangeProp, comp.state);
expect(comp.state.formData).eql("foobar");
});
});

describe("when the schema default is changed but formData is not changed", () => {
const newSchema = {
type: "string",
default: "the new default",
};

beforeEach(() =>
comp.componentWillReceiveProps({
schema: newSchema,
formData: "some value",
}));

it("should not call onChange", () => {
sinon.assert.notCalled(onChangeProp);
expect(comp.state.formData).eql("some value");
expect(comp.state.schema).deep.eql(newSchema);
});
});

describe("when the schema default is changed and formData is changed", () => {
const newSchema = {
type: "string",
default: "the new default",
};

beforeEach(() =>
comp.componentWillReceiveProps({
schema: newSchema,
formData: "something else",
}));

it("should not call onChange", () => {
sinon.assert.notCalled(onChangeProp);
expect(comp.state.formData).eql("something else");
expect(comp.state.schema).deep.eql(newSchema);
});
});

describe("when the schema default is changed and formData is nulled", () => {
const newSchema = {
type: "string",
default: "the new default",
};

beforeEach(() =>
comp.componentWillReceiveProps({ schema: newSchema, formData: null }));

it("should call onChange", () => {
sinon.assert.calledOnce(onChangeProp);
sinon.assert.calledWith(onChangeProp, comp.state);
expect(comp.state.formData).eql("the new default");
});
});
});

describe("External formData updates", () => {
describe("root level", () => {
const formProps = {
Expand Down

0 comments on commit 9813483

Please sign in to comment.