Implementation of Bootstrap grid layout into a custom field
toccoto opened this issue · comments
Description
Implementation of Bootstrap grid layout into a custom field
Hey, I've been looking at this library today, but really wanted to be able to control the grid layout of Schema, independent of how it's sent. (Basically the backend will send the schema independent of order, rows and columns) I came up with this, which works. Just wondering if there is a cleaner way I'm missing or if I'm on the right track. Thanks for the help!
import React from 'react';
import SchemaForm from 'react-jsonschema-form';
import ObjectField from 'react-jsonschema-form/lib/components/fields/ObjectField';
import {retrieveSchema} from "react-jsonschema-form/lib/utils";
import {Grid, Row, Col} from 'react-bootstrap';
class GridField extends ObjectField {
constructor(props) {
super(props);
}
render() {
const {
uiSchema,
errorSchema,
idSchema,
name,
required,
disabled,
readonly,
onBlur
} = this.props;
const {definitions, fields, formContext} = this.props.registry;
const {SchemaField, TitleField, DescriptionField} = fields;
const schema = retrieveSchema(this.props.schema, definitions);
const title = (schema.title === undefined) ? name : schema.title;
const order = uiSchema['ui:options'].order;
return (
<fieldset>
{title ? <TitleField
id={`${idSchema.$id}__title`}
title={title}
required={required}
formContext={formContext}/> : null}
{schema.description ?
<DescriptionField
id={`${idSchema.$id}__description`}
description={schema.description}
formContext={formContext}/> : null}
{
order.map((row, index) => {
return (
<div className="row" key={index}>
{
Object.keys(row).map((name, index) => (
<Col {...row[name]} key={index}>
<SchemaField
name={name}
required={this.isRequired(name)}
schema={schema.properties[name]}
uiSchema={uiSchema[name]}
errorSchema={errorSchema[name]}
idSchema={idSchema[name]}
formData={this.state[name]}
onChange={this.onPropertyChange(name)}
onBlur={onBlur}
registry={this.props.registry}
disabled={disabled}
readonly={readonly}/>
</Col>
))
}
</div>
);
})
}</fieldset>
);
}
}
const fields = {
grid: GridField,
};
const schema = {
title: "Primary Applicant",
type: "object",
properties: {
personal: {
title: "",
type: "object",
properties: {
first: {
type: "string",
title: "First"
},
mi: {
type: "string",
title: "MI"
},
last: {
type: "string",
title: "Last"
},
suffix: {
type: "string",
title: "Suffix",
enum: ['jr', 'sr'],
enumNames: ['JR', 'SR']
},
ssn: {
type: "string",
title: "ssn"
},
dob: {
type: "string",
title: "dob"
}
}
}
}
};
const getUiSchema = () => {
let order = [
{
first: { md: 5 },
mi: { md: 2 },
last: { md: 5 }
},
{
suffix: { md: 2 },
ssn: { md: 5 },
dob: { md: 5 }
}
]
return {
personal: {
"ui:field": "grid",
"ui:options": {
"order": order
}
}
}
}
export const Applicant = () => (
<div>
<h1>Applicant</h1>
<SchemaForm schema={schema} uiSchema={getUiSchema()} fields={fields}/>
</div>
);
Sorry, I couldn't get it working on jsFiddle but the end result works. I get 2 rows, with split columns.
Basically I just extend ObjectField, and add the data to split up based on the ordering info.
Any other suggestions are welcome.
Object fields are orderable using the ui:order uiSchema directive.