rjsf-team / react-jsonschema-form

A React component for building Web forms from JSON Schema.
https://rjsf-team.github.io/react-jsonschema-form/
Apache License 2.0
14.09k stars 2.18k forks source link

Passing ui options down to array items #4160

Open RAFA3L opened 5 months ago

RAFA3L commented 5 months ago

Prerequisites

What theme are you using?

chakra-ui

What is your question?

Hello, I'm using custom templates to display only plain data and I would like to add a custom uiSchema option to count the total of items in a nested array, for example

In the ArrayFieldTemplate I'm trying adding an offset index for each group into the uiSchema options, but I think these options apply for all, independently if I set it for each group., for example:

props.items.map((item, index) => {
  if (index > 0) {
    set(item, ['children', 'props', 'uiSchema', 'list', 'items', 'options'], { indexOffset: props.items[index - 1].totalItems });
  }      
  return item;
});

After that all the items have the same latest index, and I would like to pass the totalItems from the previous group to the next one.

Thanks in advanced

RAFA3L commented 5 months ago

Hello, it was a problem updating the deep nested array and I think I can solve it with something like this. Is there a better way to update this value properly? With immer I got it's only readable

const newItems: ArrayFieldTemplateItemType[] = [];
props.items.forEach((item, index) => {
  const newItem = {
    ...item,
    children: {
      ...item.children,
      props: {
        ...item.children.props,
        uiSchema: {
          ...item.children.props.uiSchema,
          list: { ...item.children.props.uiSchema.list,
            options: { ...item.children.props.uiSchema.list.options }
           }
        }
      }
    },
  }
  newItem.children.props.uiSchema.list.options.indexOffset = index;
  newItems.push(newItem);
});

props = { ...props, items: newItems };
nickgros commented 4 months ago

This is a very niche use-case. I cannot think of any feature in RJSF that would make this easier. I think your code is probably a safe way to do it, but it is hard for us to debug code you have written that is specific to your application.

RAFA3L commented 4 months ago

Thanks @nickgros ,

I'm making a workflow builder, and each node has it's own form, so I'm using RJSF to generate them easily (and the output data too). Now the idea is to show a preview of plain data on the node by leveraging on the RJSF with custom templates and widgets. And from the uiSchema I can define witch field or group of fields (even nested) will be displayed and will be a port in the node, this is why I needed to manipulate the props in runtime.

At the end I could simplify the override of props using immer by adding

setAutoFreeze(false);

and then for example:

const newItems: ArrayFieldTemplateItemType[] = [];
let totalItems = 0;
props.items.forEach((item, index) => {
  newItems.push(
    produce(item, (draft) => {
      draft.children.props.uiSchema.list.items["ui:options"].indexOffset =
        totalItems;
    })
  );
  totalItems += item.children.props.formData.list.length;
});
props = { ...props, items: newItems };

Thanks, this is a wonderful project

heath-freenome commented 2 months ago

@RAFA3L Have we answered your question? Can we close this?