How do I create a custom array layout renderer so I can provide 2+ properties to show up on the label. I was able to recreate all the other primitive renderers. I just need this one customization and I am unable to figure out how to write the custom renderer.
Hi @bert,
What exactly are you struggling with? As a starting point you can copy/paste our array renderer and then adjust it to your needs.
Right now I’m passing in the label through element label props. I thought of copy/pasting the array renderer but I wasn’t able to figure out where it takes in the element label props to show as the label. My assumption right now is I will need to edit something in the MaterialArrayLayout?
TLDR: I’m not able to figure out where to find the array layout renderer and the function which takes elementLabelProp and adjust it to my needs.
Hi @bert,
The main difficulty is that you have to copy/paste quite a lot of code to customize the label behavior.
- The registered renderer is MaterialArrayLayoutRenderer.
- It uses the MaterialArrayLayout
- Here the ui schema’s
elementLabelPropis handed over aschildLabelPropto theExpandPanelRenderer
- Here the ui schema’s
- This is the HOC wrapping the
ExpandPanelRendererComponent. It contains the logic to determine the child label and hands it over to theExpandPanelRendererComponent.
So for you to customize the label you can:
- Copy the
withContextToExpandPanelPropsHOC and adjust the label determination to your liking - Copy the
ExpandPanelRendererComponentof JSON Forms because it’s currently not exported. - Wrap the copy of the
ExpandPanelRendererComponentwith your adjusted HOC, like we do in the framework - Copy the
MaterialArrayLayout, using your custom expand panel renderer instead of the one of JSON Forms - Copy the
MaterialArrayLayoutRenderer, using your custom material array layout instead of the one of JSON Forms
Hello, I was able to create my own custom array renderer. This way I am able to access the uischema property and pass in multiple elements and create my own function that way.
However I am running into a new issue, when using the JsonFormsDispatch, it renders everything perfectly, until there is another array with expand panels inside it. I found a temporary fix, when I pass in all the material renderers, and my custom renderers for the rest of the elements, it works. The catch is that it uses MUI expand panel. When I pass in my expand panel array renderer along with mui renderers and custom renderers, it shows “No applicable renderers found”
const ArrayControl = ({data, path, schema, enabled, uischema, addItem, removeItems, rootSchema}: ArrayControlProps) => {
const label = uischema.options.elementLabelProp
const labelPropName = formatName(uischema.options.elementLabelProp)
return (
<div>
<div>
<Button>Code to add Item</Button>
</div>
{(data??[]).map(child, index)=>{
return (
<div key ={index}>
<Accordion title={labelPropName+ ' ' + child[label]}>
<JsonFormsDispatch
key={index}
schema={schema}
uischema={uischema}
enabled={enabled}
path={path? `${path}.${index}`: `${index}`}
/>
</Accordion>
</div>
)
}}
</div>
)
}
Case 1 - (No renderers passed to JsonFormsDispatch): Renders every single component properly, even renders the sub expand array inside the main expand array. Only problem is, when I expand the subarray it shows “No applicable renderers”
Case 2 - (My own custom renderers and mui renderes passed to JsonFormsDispatch, No custom arrayrenderers is passed into jsonformsdispatch): The outer expand array works, when I expand everything is my own custom stuff. The sub expand array uses MUI expand panels, but when I expand it uses my own custom componenets.
Case 3 - (I pass in all my own custom components including a copy of the custom array componenet and MUI renderers): It goes back to showing my custom component expand array at the topmost level and even the subarray is my own custom expand array, but when I expand it, it says no applicable renderers.
Consistencies:
- Outer array is always my own custom array renderers and everything inside the main array renders fine.
- Whenever I pass in a copy of my array custom component into JsonFormsDispatch, the sub array expand panel conforms to my style, but fails to render the child componenets.
Something that could be important, we are using allOf, but I checked the schema, and uischema at the subarray renderer level and it is already resolved without the allof.
Thank you for your time and help!
Usually you don’t need to hand over renderers or cells to JsonFormsDispatch. This possibility is only there for niche use cases, to render with different renderer sets within the same form or supporting a renderer which wraps all other renderers.
When renderers and cells are not handed over to JsonFormsDispatch, then it will just reuse the same renderers and cells handed over to the root JsonForms component.
Case 1 - (No renderers passed to JsonFormsDispatch): Renders every single component properly, even renders the sub expand array inside the main expand array. Only problem is, when I expand the subarray it shows “No applicable renderers”
Does it also show “No applicable renderers” when you do not use any custom renderers at all? Can you post the JSON Schema you are using?
Hello,
Whenever I am using no custom renderers it does not show this error. After testing through multiple ways, I’ve determined that the problem is definitely the custom array renderer I wrote.
It only fails when JSON Forms dispatch is using the custom array renderer I wrote. It’s also important to note that the renderer only fails at the second level (when using json forms dispatch). At the outer level it works perfectly, along with add, delete, and update actions.
Whenever I pass in MUI renderers again inside the array custom renderer to json forms dispatch, it works fine with the second level of expand array layout working as well.
These reasons are why I’m very convinced that the array renderer is the problem. Do you see any issue with my array renderer?
From what you posted your code looks fine but there is a lot of code which you did not post. Please share a full reproducible example. The easier it is to run on my system / on the web, the better and quicker I can help.
Sure, I am not able to give you a github repo but I can provide my schema and custom array renderer code. everything else is from MUI.
{
"type": "array",
"title": "OuterArray",
"items": {
"type": "object",
"properties": {
"Type": {
"type": "string",
"title": " Type"
},
"Value": {
"type": "integer",
"title": " Value"
},
"middleArray": {
"type": "array",
"title": "Subs",
"items": {
"type": "object",
"properties": {
"subType": {
"type": "string",
"title": "Sub Type"
},
"subValue": {
"type": "integer",
"title": "Sub Value"
},
"innerArray": {
"type": "array",
"title": "InnerArray",
"items": {
"type": "object",
"properties": {
"innerType": {
"type": "string",
"title": "Inner Type"
},
"innerValue": {
"type": "integer",
"title": "Inner Value"
}
}
}
}
}
}
}
}
}
}
const ArrayControl = ({data, path, schema, enabled, uischema, addItem, errors, removeItems, rootSchema, cells, renderers}: ArrayControlProps) => {
const label = useMemo(() => uischema?.options?.elementLabelProp, [uischema, path]);
const labelPropName = formatName(uischema?.options?.elementLabelProp || 'Property')
return (
<div style={{padding: '10px'}}>
<pre>{JSON.stringify(schema,null,2)}</pre>
<div>
<Button emphasis='subtle' onClick={addItem(path, createDefaultValue(schema, rootSchema))}><Icon name="add" type="filled" /></Button>
</div>
{(data??[]).map((child, index) => {
// console.log('child', child, 'index', index, 'path', path)
// console.log( 'schema', schema, 'uischema', uischema)
return (
<div key={index}>
<Accordion key={index} title={<Heading typography="heading06">{labelPropName} {child[label]}</Heading>}
customRightElement={<Button emphasis='subtle' onClick={removeItems?.(path, [index])}><Icon name="delete" type="filled" /></Button>}>
<JsonFormsDispatch
key={index}
schema={schema} // schema already points to the items because of "withJsonFormsArrayLayoutProps". If we had used the generic "withJsonFormsControlProps" we would need to hand over "schema.items" here.
uischema={uischema}
enabled={enabled} // you need to pass the enabled prop explicitly as the short hand "enabled" means that enabled is always true.
path={path ? `${path}.${index}` : `${index}`}
renderers={renderers}
cells={cells}
/>
</Accordion>
</div>
)})}
</div>
)
}
export const arrayControl = withJsonForms
export const nestedArrayControlTester = rankWith(100, isObjectArrayWithNesting)
These is pretty much everything I’ve customized regarding the array renderer
Please let me know where I am going wrong. After more experimentation I am assuming this problem is occurring in how my array control is taking in the schema. After looking at the source code, there might be difference in how I’m passing down arraycontrol props as there is material array layout renderer, material array layout, and expand panel. But I just have expand panel.