Using react-jsonschema-form
[1] we can dynamically render React
components from configuration rather than code. I.e.
const Form = JSONSchemaForm.default;
const schema = {
title: "Test form",
type: "object",
properties: {
name: {
type: "string"
},
age: {
type: "number"
}
}
};
ReactDOM.render((
<Form schema={schema} />
), document.getElementById("app"));
And we can use uiSchema
object to customize and configure the individual look of each component. Is it possible however, instead of having the form created in a linear fashion, can I obtain each individual element and position them where I want?
For example, I may want the name
field on page1
and the age
field on page3
. The only way I can think to do this currently is editing the package's source to return individual elements rather than wrapping them into the Form
object.
Maybe there is some way in React
to interrogate and extract the individual components from the Form
object?
Thanks
No, there isn't a way to get rjsf
to split a form into multiple UI components. You can emulate that behavior by making multiple forms (multiple JSON Schema schema
s). Depending on the structure of the combined output you want, it may be simplest to break the schema
down by different nested property apparent at the root level, e.g. the 1st page corresponds to the 1st key at the root level (name
), the 2nd page corresponds to the 2nd key (age
), and so on. Note that you'd have to control this pagination and navigation yourself, and also merge each page's formData
back into the singular payload you were expecting.
Here's a rough draft:
pageOneSchema = {
title: "Test form pg. 1",
type: "object",
properties: {
name: {
type: "string"
}
}
};
pageTwoSchema = {
title: "Test form pg. 2",
type: "object",
properties: {
age: {
type: "number"
}
}
};
const schemas = [pageOneSchema, pageTwoSchema];
// Your component's member functions to orchestrate the form and its "pages"
state = {
currentPage: 0,
pages: new Array(schemas.length).fill({}), // initial pages array to empty objects = unfilled forms
}
pageDataChangeHandler = (page) => {
const onChange = (e) => {
const pages = [...this.state.pages];
pages[page] = e.formData; // not too 100% about the key
this.setState({
pages,
});
}
}
getSubmitHandlerForPage = (page) => {
if (page !== schemas.length) {
// If current page is not the last page, move to next page
this.setState({
currentPage: page + 1,
});
} else {
// concat all the pages' data together to recompose the singular payload
}
}
...
const { currentPage } = this.state;
<Form
formData={this.state.pages[currentPage]}
schema={schemas[currentPage]}
onChange={this.pageDataChangeHandler(currentPage)}
onSubmit={this.getSubmitHandlerForPage(currentPage)}
/>
You can also pass children into the Form component to render your own buttons (so maybe you don't want the forms saying "Submit" instead of "Next Page" if they're not actually going to submit).
Note that if you do custom buttons and make a "Next" button, it must still be of "submit" type because of the type of event it emits (used for validation and some other things). Though there was an ask to make the text/title of the submit button easier to manipulate...