UNPKG

@bhch/react-json-form

Version:
220 lines (171 loc) 6.14 kB
import React from 'react'; import ReactDOM from 'react-dom'; import EditorState from './editorState'; import ReactJSONForm from './form'; import DataValidator from './dataValidation'; export function FormInstance(config) { this.containerId = config.containerId; this.dataInputId = config.dataInputId; this.schema = config.schema; this.data = config.data; this.errorMap = config.errorMap; this.fileHandler = config.fileHandler; this.fileHandlerArgs = config.fileHandlerArgs || {}; this.readonly = config.readonly || false; this.eventListeners = null; this._dataSynced = false; this.addEventListener = function(event, listener) { if (this.eventListeners === null) this.eventListeners = {}; if (!this.eventListeners.hasOwnProperty(event)) this.eventListeners[event] = new Set(); this.eventListeners[event].add(listener); }; this.onChange = function(e) { this.data = e.data; if (!this._dataSynced) { // this is the first change event for syncing data this._dataSynced = true; return; } if (!this.eventListeners) return; if (!this.eventListeners.hasOwnProperty('change') || !this.eventListeners.change.size) return; this.eventListeners.change.forEach((cb) => cb(e)); }; this.onChange = this.onChange.bind(this); this.render = function() { if (ReactDOM.hasOwnProperty('createRoot')) this._renderReact18(); else this._renderReact17(); }; this._renderReact17 = function() { try { ReactDOM.render( this._getFormContainerComponent(), document.getElementById(this.containerId) ); } catch (error) { ReactDOM.render( <ErrorReporter error={error} />, document.getElementById(this.containerId) ); } }; this._renderReact18 = function() { const root = ReactDOM.createRoot(document.getElementById(this.containerId)); try { root.render(this._getFormContainerComponent()); } catch (error) { root.render(<ErrorReporter error={error} />); } }; this._getFormContainerComponent = function() { return ( <FormContainer schema={this.schema} dataInputId={this.dataInputId} data={this.data} errorMap={this.errorMap} fileHandler={this.fileHandler} fileHandlerArgs={this.fileHandlerArgs} onChange={this.onChange} readonly={this.readonly} /> ); }; this.update = function(config) { this.schema = config.schema || this.schema; this.data = config.data || this.data; this.errorMap = config.errorMap || this.errorMap; this.render(); }; this.getSchema = function() { return this.schema; }; this.getData = function() { return this.data; }; this.validate = function() { let validator = new DataValidator(this.getSchema()); return validator.validate(this.getData()); }; } const FORM_INSTANCES = {}; export function createForm(config) { let instance = new FormInstance(config); // save a reference to the instance FORM_INSTANCES[config.containerId] = instance; return instance; } export function getFormInstance(id) { return FORM_INSTANCES[id]; } export class FormContainer extends React.Component { constructor(props) { super(props); this.state = { editorState: EditorState.create(props.schema, props.data), }; this.prevEditorState = this.state.editorState; this.dataInput = document.getElementById(props.dataInputId); } componentDidMount() { this.props.onChange({data: this.state.editorState.getData()}); this.populateDataInput(this.state.editorState.getData()); } componentDidUpdate(prevProps, prevState) { if (this.props.schema !== prevProps.schema) { let newSchema = this.props.schema; let newData = this.props.data !== prevProps.data ? this.props.data : this.state.editorState.getData(); this.setState({ editorState: EditorState.create(newSchema, newData) }); return; } if (this.props.data !== prevProps.data) { this.setState({ editorState: EditorState.update(this.state.editorState, this.props.data) }); return; } if (this.state.editorState !== prevState.editorState) this.populateDataInput(this.state.editorState.getData()); if (this.props.onChange && this.state.editorState !== prevState.editorState) this.props.onChange({ schema: this.state.editorState.getSchema(), data: this.state.editorState.getData(), prevSchema: prevState.editorState.getSchema(), prevData: prevState.editorState.getData() }); } populateDataInput = (data) => { this.dataInput.value = JSON.stringify(data); } handleChange = (editorState) => { this.setState({editorState: editorState}); } render() { return ( <ReactJSONForm editorState={this.state.editorState} onChange={this.handleChange} fileHandler={this.props.fileHandler} fileHandlerArgs={this.props.fileHandlerArgs} errorMap={this.props.errorMap} readonly={this.props.readonly} /> ); } } function ErrorReporter(props) { /* Component for displaying errors to the user related to schema */ return ( <div style={{color: '#f00'}}> <p>(!) {props.error.toString()}</p> <p>Check browser console for more details about the error.</p> </div> ); }