Skip to content

Commit 2d370c2

Browse files
committed
Added ability to define child keys in schema. Maintenance of cleaning up docs and linting
1 parent 4c60197 commit 2d370c2

6 files changed

Lines changed: 73 additions & 48 deletions

File tree

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
demo
12
spec/spec.js
23
*.md
34
webpack.config.spec.js

.eslintrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
{
33
"extends": "airbnb",
44
"rules": {
5-
"comma-dangle": 0,
6-
"id-length": [1, { "exceptions": ["_"] }]
5+
"comma-dangle": 0
76
}
87
}

README.md

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,60 +6,74 @@ This library constructs React elements from JSON by mapping JSON definitions to
66

77
JSX is not a dependency for react-json-schema.
88

9-
For a quick reference, you can jump to the [full example](#putting-it-all-together).
9+
[Quick Documentation](http://techniquesoftware.github.io/react-json-schema/)
1010

11-
For 0.3.0+, you must use React 0.14.0+. You may use 0.2.0 for older versions.
11+
### Full Documentation
1212

13-
### Documentation
13+
* [Schema](#schema)
14+
* [Dynamic Children and Keys](#dynamic-children-and-keys)
15+
* [Component Mapping](#component-mapping)
16+
* [Rendering](#rendering)
17+
* [Complete Example](#complete-example)
1418

1519
#### Schema
1620

1721
The primary resource needed is a defined schema in JSON or a JavaScript object literal. It's recommended that schema attributes mainly define React component props. The parser explicitly handles the following attributes:
1822
- **component**: _MUST_ exist and be defined by a string or React component (must be a string if describing a native HTML tag)
1923
- **children**: _MAY_ exist to define sub-components
2024
- **text**: _MAY_ exist to as a string to define inner HTML text (overrides children)
25+
- **key**: _MAY_ exist to define a key for dynamic children
2126

2227
Example JSON schema (ES6)
2328
```js
2429
const schema = {
25-
"component": "ContactForm",
26-
"title": "Tell us a little about yourself...",
30+
"component": "CommentList",
2731
"children": [
2832
{
29-
"component": "StringField",
30-
"label": "What's your name?"
33+
"component": "Comment",
34+
"author": "Pete Hunt",
35+
"children": "This is one comment"
36+
},
37+
{
38+
"component": "Comment",
39+
"author": "Jordan Walke",
40+
"children": "This is *another* comment"
3141
},
3242
{
3343
"component": "a",
34-
"href": "#faq",
35-
"text": "I'm not sure why I'm filling this out"
44+
"href": "#help",
45+
"text": "I need help"
3646
}
3747
]
38-
}
48+
};
3949
```
4050

4151
Example JS literal (ES6)
4252
```js
43-
const schema = {
44-
"component": ContactForm,
45-
"title": "Tell us a little about yourself...",
46-
"children": [
47-
{
48-
"component": StringField,
49-
"label": "What's your name?"
50-
},
51-
{
52-
"component": "a",
53-
"href": "#faq",
54-
"text": "I'm not sure why I'm filling this out"
55-
}
56-
]
57-
}
53+
...
54+
{
55+
"component": Comment, // literal
56+
"author": "Pete Hunt",
57+
"children": "This is one comment"
58+
},
59+
...
5860
```
5961

6062
##### Dynamic Children and Keys
6163

62-
When arrays of components exist (like children), react-json-schema will resolve a key for the element based on the array index, which follows the rules for [dynamic children](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children). Custom keys cannot be defined at this time.
64+
When arrays of components exist (like children), react-json-schema will resolve a key for the element, which follows the rules for [dynamic children](https://facebook.github.io/react/docs/multiple-components.html#dynamic-children). It will either use a custom key if defined, or resolve a numeric key based on the array index.
65+
66+
Example of defining child keys (ES6)
67+
```js
68+
...
69+
{
70+
"component": "Comment",
71+
"key": "0ab19f8e", // defined key
72+
"author": "Pete Hunt",
73+
"children": "This is one comment"
74+
},
75+
...
76+
```
6377

6478
#### Component Mapping
6579

@@ -83,27 +97,26 @@ ReactDOM.render(contactForm.parseSchema(schema),
8397

8498
##### Rendering
8599

86-
Also note react-json-schema does not perform any rendering, so the method in which you want to render is up to you. For example, you can use ReactDOMServer.render, ReactDOM.renderToString, etc. if you'd like.
100+
Since react-json-schema does not perform any rendering, the method in which you want to render is up to you. For example, you can use ReactDOMServer.render, ReactDOM.renderToString, etc. if you'd like.
87101

88-
#### Putting it All Together
102+
#### Complete Example
89103

90104
```js
91105
import ReactDOM from 'react-dom';
92106
import ReactJsonSchema from 'react-json-schema';
93107

94-
import FormStore from './stores/FormStore';
95-
import ContactForm from './components/ContactForm';
96-
import StringField from './components/StringField';
108+
import FormStore from 'FormStore';
109+
import CommentList from 'CommentList';
110+
import Comment from 'Comment';
97111

98112
// For this example, let's pretend I already have data and am ignorant of actions
99113
const schema = FormStore.getFormSchema();
100-
const componentMap = { ContactForm, StringField }
114+
const view = new ReactJsonSchema();
101115

102-
const contactForm = new ReactJsonSchema();
103-
contactForm.setComponentMap(componentMap);
116+
view.setComponentMap({ CommentList, Comment });
104117

105-
ReactDOM.render(contactForm.parseSchema(schema),
106-
document.getElementById('contact-form'));
118+
ReactDOM.render(view.parseSchema(schema),
119+
document.getElementById('content'));
107120
```
108121

109122
### Try the Demo
@@ -122,4 +135,4 @@ Please use a linter that recognizes eslint rules
122135

123136
### Roadmap
124137

125-
* Support custom keys for children
138+
* Possibility of react-native-json-schema

demo/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ const formSchema = {
3030
'checkboxes': [
3131
{
3232
'label': 'I\'m already checked!',
33-
'defaultChecked': true
33+
'defaultChecked': true,
34+
'key': 0
3435
},
3536
{
36-
'label': 'Here\'s another'
37+
'label': 'Here\'s another',
38+
'key': 10
3739
}
3840
]
3941
}

lib/ReactJsonSchema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class ReactJsonSchema {
1919
const Components = [];
2020
let index = 0;
2121
for (const subSchema of subSchemas) {
22-
subSchema.key = index;
22+
subSchema.key = typeof subSchema.key !== 'undefined' ? subSchema.key : index;
2323
Components.push(this.parseSchema(subSchema));
2424
index++;
2525
}

spec/ReactJsonSchemaSpec.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* global jasmine, beforeEach, describe, it, expect, fail, spyOn */
2+
/* eslint max-len: 0 */
23

34
import React from 'react';
45
import ReactJsonSchema from '../lib/ReactJsonSchema';
@@ -7,18 +8,18 @@ let reactJsonSchema;
78
let schema;
89

910
export default describe('ReactJsonSchema', () => {
10-
const Tester = React.createClass({
11-
render: () => {
12-
return React.createElement('h1', null, 'Tester!!!!');
13-
}
11+
const Tester = React.createClass({ // eslint-disable-line
12+
render: () => React.createElement('h1', null, 'Tester!!!!')
1413
});
1514

1615
beforeEach(() => {
1716
reactJsonSchema = new ReactJsonSchema();
17+
/* eslint-disable */
1818
schema = {
19-
'component': Tester,
20-
'someProp': 'I\'m a tester'
19+
"component": Tester,
20+
"someProp": "I'm a tester"
2121
};
22+
/* eslint-enable */
2223
});
2324
describe('when parsing schema', () => {
2425
it('should return an array of React elements when schema\'s root type is of type array.', () => {
@@ -49,6 +50,15 @@ export default describe('ReactJsonSchema', () => {
4950
reactJsonSchema.parseSubSchemas(subSchemas);
5051
expect(reactJsonSchema.parseSchema).toHaveBeenCalled();
5152
});
53+
it('should consume a key defined in the schema\'s keys for the current sub-schema based on the current sub-schema\'s index to meet React\'s key expectation of multiple React elements.', () => {
54+
const schemaClone = Object.assign({}, schema);
55+
const subSchemas = [schemaClone, schemaClone];
56+
for (const subSchema of subSchemas) { subSchema.key = Math.random(); }
57+
spyOn(reactJsonSchema, 'parseSchema');
58+
reactJsonSchema.parseSubSchemas(subSchemas);
59+
expect(reactJsonSchema.parseSchema).toHaveBeenCalledWith(subSchemas[0]);
60+
expect(reactJsonSchema.parseSchema).toHaveBeenCalledWith(subSchemas[1]);
61+
});
5262
it('should assign a key to the current sub-schema based on the current sub-schema\'s index to meet React\'s key expectation of multiple React elements.', () => {
5363
spyOn(reactJsonSchema, 'parseSchema');
5464
const schemaClone = Object.assign({}, schema);

0 commit comments

Comments
 (0)