Search code examples
reactjsdynamic-arraysnested-checkboxes

How i render checkboxes with nested array of objects


I have a checkbox component which renders multiple day checkboxes. I need to print the values of the selected checkboxes. The sample given below looks like the one:

const [state, setState] = useState({ 
    "firstName": "",
    "lastName" : "",
    "mobileNumber" : "",
    "avalabilities": [{"availabilityId": "",

    day: [
      {
        value: "sun",
        name: "Sunday"
      },
      {
        value: "mon",
        name: "Monday"
      },
      {
        value: "tue",
        name: "Tuesday"
      },
      {
        value: "wed",
        name: "Wednesday"
      },
      {
        value: "thur",
        name: "Thursday"
      },
      {
        value: "fri",
        name: "Friday"
      },
      {
        value: "sat",
        name: "Saturday"
      }
    ],
    "isChecked": false,
    "checked" : false,
    "allChecked": false,
    "error": null});

this is the console value given below

{firstName: '', lastName: '', mobileNumber: '', avalabilities: Array(1), …}
allChecked: false
avalabilities: Array(1)
0:
availabilityId: ""
day: (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
[[Prototype]]: Object
length: 1
[[Prototype]]: Array(0)
close: false
disabled: false
error: null
firstName: ""
isChecked: false
isPending: false
lastName: ""
mobileNumber: ""
open: false

this is how I am trying to render the arrays

{(avalabilities ||  [{}]).map((av, index) => {
    return (
      <div key={av.availabilityId}>


<>
            {av.day.map((item) => {
              return (
                <div>
                  <input
                    checked={item.checked || false}
                    onChange={() => handleChange3(item.value)}
                    type="checkbox"
                  />
                </div>
              );
            })}
          </>

But the error on mapping with day array is coming below like this

are not valid as a React child (found: object with keys {value, name}). If you meant to render a collection of children, use an array instead.

const checkedHandler = (event) => {
        
        setState(...)
        
        //Well, here I don't know how change the particular value of the 
     array...}

Any help is highly appreciated.


Solution

  • If i'm correct you want to show values of each checkbox and save the respective checkbox value when we toggle any checkbox. You have avalabilities array & in each object we have another day array. I render the all the avalabilities. Now when i toggle any checkbox, i pass three things to checkHandler:

    1. e which is native event of checkbox
    2. avIndex which is index of object in avalabilities array
    3. index which is index of object in day array.

    Now each day object, i set a key checked and store the value of that checkbox by getting the value from e.target.checked.

    Hope this solve your problem

    newState.avalabilities[avIndex].day[index].checked = e.target.checked;
    
    import { useState } from 'react';
    
    export default function App() {
        const [state, setState] = useState({
            firstName: '',
            lastName: '',
            mobileNumber: '',
            avalabilities: [
                {
                    availabilityId: '',
                    day: [
                        { value: 'sun', name: 'Sunday' },
                        { value: 'mon', name: 'Monday' },
                        { value: 'tue', name: 'Tuesday' },
                        { value: 'wed', name: 'Wednesday' },
                        { value: 'thur', name: 'Thursday' },
                        { value: 'fri', name: 'Friday' },
                        { value: 'sat', name: 'Saturday' }
                    ],
                    isChecked: false,
                    checked: false,
                    allChecked: false,
                    error: null
                }
            ]
        });
    
        const checkedHandler = (e, avIndex, index) => {
            console.log(e.target.checked, avIndex, index);
            setState((prev) => {
                let newState = { ...prev };
                newState.avalabilities[avIndex].day[index].checked = e.target.checked;
                return newState;
            });
        };
    
        return (
            <>
                {state.avalabilities.map((av, avIndex) => (
                    <div key={av.availabilityId}>
                        {av.day.map((item, index) => (
                            <div key={index}>
                                <input
                                    checked={item?.checked || false}
                                    onChange={(e) => checkedHandler(e, avIndex, index)}
                                    type='checkbox'
                                />
                                <span>{item.name}</span>
                            </div>
                        ))}
                    </div>
                ))}
            </>
        );
    }