Hi there SO!
I'm currently trying to make a form that generates based on the object supplied and this seem to work at just about anything I throw at it.
That is, until I get to a nested object.
The problem:
Once I hit the if condition (typeof value === "object")
I want to have a hidden input (this works).
Then I want to go into that object I just identified, and into all child objects it may contain and generate the input on same criteria as the initial run-through.
function GenericForm(props: any) {
var object = props.object;
return (
<div>
<form>
{Object.entries(object).map(([property, value]) => {
let type: string = "";
if (typeof value === "string") {
type = "text";
} else if (typeof value === "number") {
type = "number";
} else if (typeof value === "boolean") {
type = "checkbox";
} else if (value instanceof Date) {
type = "date";
} else if (typeof value === "object") {
type = "hidden";
}
return [
<label property={property} htmlFor={property}>
{property}
</label>,
<input
type={type}
id={property}
name={property}
defaultValue={value as string}
onChange={(newVal) => {
object[property] = newVal.target.value;
}}
/>,
];
})}
</form>
</div>
);
}
export default GenericForm;
I'm aware that this most likely utilizes some kind of recursion and while I have tried to solve it using recursion, I haven't been able to solve it.
the code pasted here is from before I tried recursion, to have a "clean sheet" from where it went wrong for me.
EDIT 1 - added info on object structure
the object passed should be completely generic and allow for objects of any structure to be handed to the component, currently it should then just evaluate what type the properties are and make an input element from that.
one of the current objects I'm passing have the following JSON Schema
{
"id": "XYZ1",
"type": "twilio-api",
"sid": "someSID",
"from": " phonenumberhere",
"name": "TWILIO SMS",
"credentials": {
"token": "someapitoken"
}
}
above object currently renders like so:
CodePudding user response:
Assuming you have a Input
component:
function Input = ({ name, type, value }) => {
// most of your code can fit here
return <input name={name} type={type} value={value} />
}
You can use your version of code, I use a simplified version as above to make our discussion easier. With that we can design a InputList
component:
function InputList = ({ object }) => {
console.log('list', object)
return (
<div>
{Object.entries(object).map(([property, value]) => {
if (typeof value === "object") {
return <InputList object={value} />
} else {
return <Input name={property} />
}
})}
</div>
)
}
You can see inside this InputList
, there's a call to InputList
again, so that is the recursion you are looking for. The recursion stops when you don't have an object inside an object any more.
NOTE: React requires value
and onChange
to drive any input
box. Otherwise they'll just behave like a native input. But this is not part of this question.