Skip to content

Commit 97f30d3

Browse files
dehlin1k0
authored andcommitted
Add an array field template component (rjsf-team#437)
1 parent dad60a9 commit 97f30d3

File tree

8 files changed

+465
-136
lines changed

8 files changed

+465
-136
lines changed

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
4949
- [Form attributes](#form-attributes)
5050
- [Advanced customization](#advanced-customization)
5151
- [Field template](#field-template)
52+
- [Array field template](#array-field-template)
5253
- [Custom widgets and fields](#custom-widgets-and-fields)
5354
- [Custom widget components](#custom-widget-components)
5455
- [Custom component registration](#custom-component-registration)
@@ -700,6 +701,58 @@ The following props are passed to a custom field template component:
700701

701702
> Note: you can only define a single field template for a form. If you need many, it's probably time to look at [custom fields](#custom-field-components) instead.
702703
704+
### Array Field Template
705+
706+
Similarly to the `FieldTemplate` you can use an `ArrayFieldTemplate` to customize how your
707+
arrays are rendered. This allows you to customize your array, and each element in the array.
708+
709+
```jsx
710+
function ArrayFieldTemplate(props) {
711+
return (
712+
<div>
713+
{props.items.map(element => element.children)}
714+
{props.canAdd && <button onClick={props.onAddClick}></button>}
715+
</div>
716+
);
717+
}
718+
719+
render((
720+
<Form schema={schema}
721+
ArrayFieldTemplate={ArrayFieldTemplate} />,
722+
), document.getElementById("app"));
723+
```
724+
725+
Please see [customArray.js](https://github.com/mozilla-services/react-jsonschema-form/blob/master/playground/samples/customArray.js) for a better example.
726+
727+
The following props are passed to each `ArrayFieldTemplate`:
728+
729+
- `DescriptionField`: The generated `DescriptionField` (if you wanted to utilize it)
730+
- `TitleField`: The generated `TitleField` (if you wanted to utilize it).
731+
- `canAdd`: A boolean value stating whether new elements can be added to the array.
732+
- `className`: The className string.
733+
- `disabled`: A boolean value stating if the array is disabled.
734+
- `idSchema`: Object
735+
- `items`: An array of objects representing the items in the array. Each of the items represent a child with properties described below.
736+
- `onAddClick: (event) => (event) => void`: Returns a function that adds a new item to the array.
737+
- `readonly`: A boolean value stating if the array is readonly.
738+
- `required`: A boolean value stating if the array is required.
739+
- `schema`: The schema object for this array.
740+
- `title`: A string value containing the title for the array.
741+
742+
The following props are part of each element in `items`:
743+
744+
- `children`: The html for the item's content.
745+
- `className`: The className string.
746+
- `disabled`: A boolean value stating if the array item is disabled.
747+
- `hasMoveDown`: A boolean value stating whether the array item can be moved down.
748+
- `hasMoveUp`: A boolean value stating whether the array item can be moved up.
749+
- `hasRemove`: A boolean value stating whether the array item can be removed.
750+
- `hasToolbar`: A boolean value stating whether the array item has a toolbar.
751+
- `index`: A number stating the index the array item occurs in `items`.
752+
- `onDropIndexClick: (index) => (event) => void`: Returns a function that removes the item at `index`.
753+
- `onReorderClick: (index, newIndex) => (event) => void`: Returns a function that swaps the items at `index` with `newIndex`.
754+
- `readonly`: A boolean value stating if the array item is readonly.
755+
703756
### Custom widgets and fields
704757

705758
The API allows to specify your own custom *widget* and *field* components:

playground/app.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,11 @@ class App extends Component {
283283
}
284284

285285
load = (data) => {
286+
// Reset the ArrayFieldTemplate whenever you load new data
287+
const { ArrayFieldTemplate } = data;
286288
// force resetting form component instance
287289
this.setState({form: false},
288-
_ => this.setState({...data, form: true}));
290+
_ => this.setState({...data, form: true, ArrayFieldTemplate}));
289291
};
290292

291293
onSchemaEdited = (schema) => this.setState({schema});
@@ -314,7 +316,8 @@ class App extends Component {
314316
liveValidate,
315317
validate,
316318
theme,
317-
editor
319+
editor,
320+
ArrayFieldTemplate
318321
} = this.state;
319322

320323
return (
@@ -352,6 +355,7 @@ class App extends Component {
352355
<div className="col-sm-5">
353356
{!this.state.form ? null :
354357
<Form
358+
ArrayFieldTemplate={ArrayFieldTemplate}
355359
liveValidate={liveValidate}
356360
schema={schema}
357361
uiSchema={uiSchema}

playground/samples/customArray.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React, { Component } from "react";
2+
3+
function ArrayFieldTemplate(props) {
4+
return (
5+
<div className={props.className}>
6+
7+
{props.items && props.items.map(element => (
8+
<div key={element.index}>
9+
<div>{element.children}</div>
10+
{element.hasMoveDown &&
11+
<button onClick={element.onReorderClick(element.index, element.index + 1)}>Down</button>}
12+
{element.hasMoveUp &&
13+
<button onClick={element.onReorderClick(element.index, element.index - 1)}>Up</button>}
14+
<button onClick={element.onDropIndexClick(element.index)}>Delete</button>
15+
<hr />
16+
</div>
17+
))}
18+
19+
{props.canAdd &&
20+
<div className="row">
21+
<p className="col-xs-3 col-xs-offset-9 array-item-add text-right">
22+
<button onClick={props.onAddClick} type="button">Custom +</button>
23+
</p>
24+
</div>}
25+
26+
</div>
27+
);
28+
}
29+
30+
module.exports = {
31+
schema: {
32+
title: "Custom array of strings",
33+
type: "array",
34+
items: {
35+
type: "string"
36+
}
37+
},
38+
formData: ["react", "jsonschema", "form"],
39+
ArrayFieldTemplate
40+
};

playground/samples/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import date from "./date";
1212
import validation from "./validation";
1313
import files from "./files";
1414
import single from "./single";
15+
import customArray from "./customArray";
1516

1617
export const samples = {
1718
Simple: simple,
@@ -27,5 +28,6 @@ export const samples = {
2728
"Date & time": date,
2829
Validation: validation,
2930
Files: files,
30-
Single: single
31+
Single: single,
32+
"Custom Array": customArray
3133
};

src/components/Form.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export default class Form extends Component {
119119
return {
120120
fields: {...fields, ...this.props.fields},
121121
widgets: {...widgets, ...this.props.widgets},
122+
ArrayFieldTemplate: this.props.ArrayFieldTemplate,
122123
FieldTemplate: this.props.FieldTemplate,
123124
definitions: this.props.schema.definitions || {},
124125
formContext: this.props.formContext || {},
@@ -184,6 +185,7 @@ if (process.env.NODE_ENV !== "production") {
184185
PropTypes.object,
185186
])),
186187
fields: PropTypes.objectOf(PropTypes.func),
188+
ArrayFieldTemplate: PropTypes.func,
187189
FieldTemplate: PropTypes.func,
188190
onChange: PropTypes.func,
189191
onError: PropTypes.func,

0 commit comments

Comments
 (0)