Repository: mozilla-services/react-jsonschema-form
Pull request #1053 (2018-10-18 16:42:14)

Update Readme with useful docs from #1050
This has been a regular source of confusion on my own organization, so I figured it was about time to help summarize it in one place.

### Reasons for making this change

Comparison tables are an effective way to succinctly compare concepts.

### Checklist

* [x] **I'm updating documentation**
  - [x] I've checked the rendering of the Markdown text I've added
  - [ ] If I'm adding a new section, I've updated the Table of Content
* [ ] **I'm adding or updating code**
  - [ ] I've added and/or updated tests
  - [ ] I've updated docs if needed
  - [ ] I've run `npm run cs-format` on my branch to conform my code to [prettier](https://github.com/prettier/prettier) coding style
* [ ] **I'm adding a new feature**
  - [ ] I've updated the playground with an example use of the feature



Patch:
diff --git a/README.md b/README.md
index d1c21e276..bdf147228 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
         - [Form data changes](#form-data-changes)
         - [Form field blur events](#form-field-blur-events)
         - [Form field focus events](#form-field-focus-events)
+     - [Submit form programmatically](#submit-form-programmatically)
   - [Form customization](#form-customization)
      - [The uiSchema object](#the-uischema-object)
      - [Alternative widgets](#alternative-widgets)
@@ -59,6 +60,7 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
      - [Field labels](#field-labels)
      - [HTML5 Input Types](#html5-input-types)
      - [Form attributes](#form-attributes)
+     - [Form disable](#form-disable)
   - [Advanced customization](#advanced-customization)
      - [Field template](#field-template)
      - [Array Field Template](#array-field-template)
@@ -240,6 +242,22 @@ Sometimes you may want to trigger events or modify external state when a field h
 
 Sometimes you may want to trigger events or modify external state when a field has been focused, so you can pass an `onFocus` handler, which will receive the id of the input that is focused and the field value.
 
+### Submit form programmatically
+You can use the reference to get your `Form` component and call the `submit` method to submit the form programmatically without a submit button.
+This method will dispatch the `submit` event of the form, and the function, that is passed to `onSubmit` props, will be called.
+
+```js
+const onSubmit = ({formData}) => console.log("Data submitted: ",  formData);
+let yourForm;
+
+render((
+  <Form schema={schema}
+        onSubmit={onSubmit} ref={(form) => {yourForm = form;}}/>
+), document.getElementById("app"));
+
+yourForm.submit();
+```
+
 ## Form customization
 
 ### The `uiSchema` object
@@ -881,8 +899,29 @@ The `Form` component supports the following html attributes:
   schema={} />
 ```
 
+### Form disable
+
+Its possible to disable the whole form by setting the `disabled` prop. The `disabled` prop is then forwarded down thru each field of the form. 
+
+```jsx
+<Form
+  disabled
+  schema={} />
+```
+
+If you just want to disable some of the fields see the `ui:disabled` parameter in the uiSchema directive. 
+
 ## Advanced customization
 
+
+_ | Custom Field  | Custom Template | Custom Widget
+--|---------- | ------------- | ----
+What it does | Overrides all behaviour | Overrides just the layout | Overrides just the input box (not layout, labels, or help, or validation)
+Usage | Global or per-field | Only global | Global or per-field
+Global Example | `<Form fields={MyCustomFields} />` |  `<Form ArrayFieldTemplate={ArrayFieldTemplate} />` | `<Form widgets={MyCustomWidgets} />`
+Per-Field Example | `"ui:field": MyField` |  N/A | `"ui:widget":MyWidget`
+Documentation | [Field](#field-props) | [Field Template](#field-template) - [Array Template](#array-field-template) - [Object Template](#object-field-template) - [Error List Template](#error-list-template) | [Custom Widgets](#custom-widget-components)
+
 ### Field template
 
 To take control over the inner organization of each field (each form row), you can define a *field template* for your form.
@@ -1001,7 +1040,7 @@ function ObjectFieldTemplate(props) {
     <div>
       {props.title}
       {props.description}
-      {props.properties.map(element => <div className="property-wrapper">{element.children}</div>)}
+      {props.properties.map(element => <div className="property-wrapper">{element.content}</div>)}
     </div>
   );
 }
diff --git a/playground/app.js b/playground/app.js
index c86616b99..bf4f868c3 100644
--- a/playground/app.js
+++ b/playground/app.js
@@ -21,7 +21,13 @@ import "codemirror/theme/eclipse.css";
 const log = type => console.log.bind(console, type);
 const fromJson = json => JSON.parse(json);
 const toJson = val => JSON.stringify(val, null, 2);
-const liveValidateSchema = { type: "boolean", title: "Live validation" };
+const liveSettingsSchema = {
+  type: "object",
+  properties: {
+    validate: { type: "boolean", title: "Live validation" },
+    disable: { type: "boolean", title: "Disable whole form" },
+  },
+};
 const cmOptions = {
   theme: "default",
   height: "auto",
@@ -323,7 +329,10 @@ class App extends Component {
       validate,
       editor: "default",
       theme: "default",
-      liveValidate: true,
+      liveSettings: {
+        validate: true,
+        disable: false,
+      },
       shareURL: null,
     };
   }
@@ -373,7 +382,7 @@ class App extends Component {
     });
   };
 
-  setLiveValidate = ({ formData }) => this.setState({ liveValidate: formData });
+  setLiveSettings = ({ formData }) => this.setState({ liveSettings: formData });
 
   onFormDataChange = ({ formData }) =>
     this.setState({ formData, shareURL: null });
@@ -396,7 +405,7 @@ class App extends Component {
       schema,
       uiSchema,
       formData,
-      liveValidate,
+      liveSettings,
       validate,
       theme,
       editor,
@@ -415,9 +424,9 @@ class App extends Component {
             </div>
             <div className="col-sm-2">
               <Form
-                schema={liveValidateSchema}
-                formData={liveValidate}
-                onChange={this.setLiveValidate}>
+                schema={liveSettingsSchema}
+                formData={liveSettings}
+                onChange={this.setLiveSettings}>
                 <div />
               </Form>
             </div>
@@ -457,7 +466,8 @@ class App extends Component {
             <Form
               ArrayFieldTemplate={ArrayFieldTemplate}
               ObjectFieldTemplate={ObjectFieldTemplate}
-              liveValidate={liveValidate}
+              liveValidate={liveSettings.validate}
+              disabled={liveSettings.disable}
               schema={schema}
               uiSchema={uiSchema}
               formData={formData}
diff --git a/src/components/Form.js b/src/components/Form.js
index b233621b1..0a7126827 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -18,6 +18,7 @@ export default class Form extends Component {
     uiSchema: {},
     noValidate: false,
     liveValidate: false,
+    disabled: false,
     safeRenderCompletion: false,
     noHtml5Validate: false,
     ErrorList: DefaultErrorList,
@@ -32,6 +33,7 @@ export default class Form extends Component {
     ) {
       this.props.onChange(this.state);
     }
+    this.formElement = null;
   }
 
   componentWillReceiveProps(nextProps) {
@@ -185,6 +187,12 @@ export default class Form extends Component {
     };
   }
 
+  submit() {
+    if (this.formElement) {
+      this.formElement.dispatchEvent(new Event("submit"));
+    }
+  }
+
   render() {
     const {
       children,
@@ -200,6 +208,7 @@ export default class Form extends Component {
       enctype,
       acceptcharset,
       noHtml5Validate,
+      disabled,
     } = this.props;
 
     const { schema, uiSchema, formData, errorSchema, idSchema } = this.state;
@@ -218,7 +227,10 @@ export default class Form extends Component {
         encType={enctype}
         acceptCharset={acceptcharset}
         noValidate={noHtml5Validate}
-        onSubmit={this.onSubmit}>
+        onSubmit={this.onSubmit}
+        ref={form => {
+          this.formElement = form;
+        }}>
         {this.renderErrors()}
         <_SchemaField
           schema={schema}
@@ -232,6 +244,7 @@ export default class Form extends Component {
           onFocus={this.onFocus}
           registry={registry}
           safeRenderCompletion={safeRenderCompletion}
+          disabled={disabled}
         />
         {children ? (
           children


Test patch:
diff --git a/test/Form_test.js b/test/Form_test.js
index d90de7aed..630026a82 100644
--- a/test/Form_test.js
+++ b/test/Form_test.js
@@ -1746,6 +1746,33 @@ describe("Form", () => {
     });
   });
 
+  describe("Form disable prop", () => {
+    const schema = {
+      type: "object",
+      properties: {
+        foo: { type: "string" },
+        bar: { type: "string" },
+      },
+    };
+    const formData = { foo: "foo", bar: "bar" };
+
+    it("should enable all items", () => {
+      const { node } = createFormComponent({ schema, formData });
+
+      expect(node.querySelectorAll("input:disabled")).to.have.length.of(0);
+    });
+
+    it("should disable all items", () => {
+      const { node } = createFormComponent({
+        schema,
+        formData,
+        disabled: true,
+      });
+
+      expect(node.querySelectorAll("input:disabled")).to.have.length.of(2);
+    });
+  });
+
   describe("Attributes", () => {
     const formProps = {
       schema: {},