React-Native - Dynamically generating a form with tcomb-form using an Array of objects

640 Views Asked by At

I'm creating a tcomb-form through an array of objects but I don't have a lot of experience with it and honestly I'm struggling a little bit to get hang of it.

This is the array structure that we are going to use:

export const AUDIT_CONTENT = 
  [
    {type: "label", style: "title", group: "4.1", text: "field text here"}, 
    {type: "label", style: "label", group: "4.1", text: "field text here"},
    {type: "multi-checkbox", style: "checkbox", group: "4.1", text: "field text here"},
    {type: "multi-checkbox", style: "checkbox", group: "4.1", text: "field text here"},
    {type: "multi-checkbox", style: "checkbox", group: "4.1", text: "field text here"},
    {type: "label", style: "label", group: "4.1", text: "field text here"},
    {type: "multi-checkbox", style: "checkbox", group: "4.1", text: "field text here"}
  ]

The fields with type: label are objects that are going to store fields type: multi-checkbox, and these fields are the ones that are going to be validated. I'm grouping those fields by group, so all fields with group 4.1 are inside an array, the fields with group 4.1 as well and so on.

I managed to dynamically generate those fields by doing the following:

myFields = () => {
  for (var c = 0; c < groupedFields.length; c++) {
    for (var i = 0; i < groupedFields[c].length; i++ ) {
      if (groupedFields[c][i].type === 'multi-checkbox') {
        fields[groupedFields[c][i].text] = t.maybe(t.enums({
                OPTION_1 : "OPTION 1 Label",
                OPTION_2 : "OPTION 2 Label",
                OPTION_3 : "OPTION 3 Label",
                OPTION_4 : "OPTION 4 Label"
        }));
      }
    }
  }
}
var fields = {};
myFields()
var myFormType = t.struct(fields);

Now my problem starts here. I'm only generation the fields that receive a value, in this case the ones with type: multi-checkbox, but, I also want to dynamically render in my form the fields with type: label in the same order as my AUDIT_CONTENT array with those being objects so the result will be something like this:

    "Field with style title": {
      "Field with style label": [
         {"Field with style multi-checkbox": "OPTION_1"},
         {"Field with style multi-checkbox": "OPTION_3"},
      ],
      "Other field with style label": [
         {"Field with style multi-checkbox": "OPTION_4"},
         {"Field with style multi-checkbox": "OPTION_2"},
      ]
    }

This result will be stored in Mongo. Hope someone can help me out with this and thanks in advance.

1

There are 1 best solutions below

1
On

It would be better if you provide a visual representation of what you want but i think that you want to render and update a nested structure. For this i recommend recursive map methods for the array.

/*
To render a structure like this you can use map and assign types to the objects to decide what to render 
But you should render it all.
Maybe you can use something like this:
*/
renderInputs(array){
    return array.map((obj) => {
        /* You can generate even nested forms if you want */
        if (obj.children) {
            return <div> {this.renderInputs()}</div>
        } else {
            return renderType(obj)
        }
    })
}

renderType(obj){
    switch (obj.type) {
        case 'label':
            return <Element  {...objProps} />
        case 'multi-checkbox':
            return <Element2 {...objProps} />
        /*You even can generate other methods for nested objects*/
        case 'other-case':
            return <div>{this.OtherSpecialSubRenderMethodIfYoUwANT()}</div>
    }
}

/**You will need an recursive method to update your state also and each object is recomended to have an unique id*/
updateState(array = this.state.array, newValue, id){
    return array.map((obj) => {
        if (obj.children) {
            return updateState(obj.children, newValue, id)
        }
        if (obj.id == id) {
            return { ...obj, value: newValue }
        }
        return obj;
    })
}