Creating Object components
AutoViews does not come with pre-made components to render objects (doing so will defeat the idea of using your own components). However, AutoViews provides utilities and APIs to create your own components to render objects.
The simplest object component will be
new ComponentsRepo('ObjectRepo').register('object', {
name: 'obj',
component: props => <AutoFields {...props} />
});
AutoFields
AutoFields
is a utility element used to render the fields of an object.
Each object field is matched with the JSONSchema
fields by field names.
Internally it apply AutoViews
for each of the fields of the object.
AutoFields
props
- extending
AutoViewProps
- getting the same properties asAutoViews
render
- optional callback to apply to each of the rendered object fields
the render function
declare function render(
item: React.ReactNode,
props: AutoViewProps,
key: string
): React.ReactNode;
The render callback parameters
item
- the rendered item, rendered usingAutoViews
.props
- theAutoViewProps
used to render the object field.key
- the field name in the object
Example - simple form rendering
new ComponentsRepo('ObjectRepo')
.register('string', {
name: 'StringComponent',
component: props => <input value={props.value} />
})
.register('number', {
name: 'NumberComponent',
component: props => (
<input
value={props.value}
type="number"
/>
)
})
.register('object', {
name: 'FormComponent',
component: props => (
<form>
<AutoFields {...props} />
</form>
)
});
Example - rendering form for array objects
This example shows how to render a form for an object which is a member of an array.
To do so, we need to specify to AutoFields
which part of the schema to use
to render the form, for instance for a new item form (new item to be added to the array).
The example is using the extractItemUISchema
and createUISchema
utility functions
imported from AutoViews
to extract the array items schema from the root schema
(extract userSchema
from usersSchema
)
Such a form will be using such a component
new ComponentsRepo('ObjectRepo')
.register('string', {
name: 'StringComponent',
component: props => <input value={props.value} />
})
.register('number', {
name: 'NumberComponent',
component: props => (
<input
value={props.value}
type="number"
/>
)
})
.register('object', {
name: 'FormComponent',
component: props => (
<form>
<AutoFields
{...props}
uiSchema={extractItemUISchema(props.uiSchema ?? createUISchema())}
/>
</form>
)
});
For reference, the schema used is something like the below schema
const userSchema: CoreSchemaMetaSchema = {
$id: 'userSchema',
type: 'object',
properties: {
firstName: {
type: 'string',
title: 'First Name'
},
lastName: {
type: 'string',
title: 'Last Name'
},
age: {
type: 'number',
title: 'Age'
},
active: {
type: 'boolean',
title: 'Is User Active'
}
},
required: ['firstName', 'lastName', 'age']
};
export const usersSchema: CoreSchemaMetaSchema = {
type: 'array',
title: 'Users',
items: userSchema
};
Example - using the render function to add field titles
new ComponentsRepo('ObjectRepo')
.register('string', {
name: 'StringComponent',
component: props => <input value={props.value} />
})
.register('number', {
name: 'NumberComponent',
component: props => (
<input
value={props.value}
type="number"
/>
)
})
.register('object', {
name: 'FormComponent',
component: props => (
<form>
<AutoFields
{...props}
render={node => (
<>
<span>{props.schema.title}</span>
node
</>
)}
/>
</form>
)
});
Example - grouping different input fields using 'UISchema'
export const FormComponent = (props: AutoViewProps) => {
const itemUISchema = extractItemUISchema(props.uiSchema ?? createUISchema());
const UISchemaAcessor = createUISchemaAccessor(
itemUISchema,
'',
ACCESSOR_TYPES.object
);
const allProperties = Object.keys(props.schema.properties!);
const groups = UISchemaAcessor.getGroups() ?? [];
const groupNames = groups.map(({name}) => name).concat([UNGROUPED]);
return (
<form>
{groupNames.map(name => {
const fields = getPropertiesByGroupName(
groups,
name,
allProperties
).filter(field => allProperties.includes(field));
if (!fields.length) return null;
return (
<div
className="group"
key={name}
>
<AutoFields
{...props}
uiSchema={itemUISchema}
pick={fields}
/>
</div>
);
})}
</form>
);
};
new ComponentsRepo('ObjectRepo')
.register('string', {
name: 'StringComponent',
component: props => <input value={props.value} />
})
.register('number', {
name: 'NumberComponent',
component: props => (
<input
value={props.value}
type="number"
/>
)
})
.register('object', {
name: 'FormComponent',
component: FormComponent
});
For reference, the above form can use the JSONSchema
const userSchema: CoreSchemaMetaSchema = {
$id: 'userSchema',
type: 'object',
properties: {
firstName: {
type: 'string',
title: 'First Name'
},
lastName: {
type: 'string',
title: 'Last Name'
},
age: {
type: 'number',
title: 'Age'
},
active: {
type: 'boolean',
title: 'Is User Active'
}
},
required: ['firstName', 'lastName', 'age']
};
and the UISchema
export const hintsSchema: UISchema = {
hints: {
'/': {
order: ['age'],
uiGroups: [
{
name: 'personalData',
title: 'Personal Data',
fields: ['firstName', 'lastName']
},
{
name: 'other',
title: 'Other Fields',
fields: [OTHER_PROPERTIES]
}
]
}
},
components: {}
};