1

When I click on add and a modal appears then I can fill that and everything is okay. But when I open a modal by clicking on a newly created data and then when I click the save button then maximum call stack exceed appears. I saw that when I'm changing subDpFormData state then it is okay, but as soon as I click on the save button somehow the subDpFormData is changed to a infinity nested object. How can I solve that?



const dpTypes = [
    'ENUM',
    'STRING',
    'FLOAT',
    'INTEGER',
    'BOOLEAN',
    'DATE',
    'IMAGE',
    'FILE_FIELD',
    'DIVISION',
    'DISTRICT',
    'UPAZILLA',
    'UNION',
    'ADDRESS',
    'EMAIL',
    'AUDIO'
]

const mainInitialData = {
    "name": "",
    "type": "",
    "label": "",
    "description": "",
    "dependent_child": null,
    "dependent_parent": null,
    "min_value": null,
    "max_value": null,
    "options": [],
    "regex": null,
    "is_in_progress": false,
    "is_single_valued": false,
    "primary_dp_list": [],
    "sub_data_point_list": []

}

const initialData = {
    "name": "test",
    "type": "",
    "label": "",
    "description": "",
    "dependent_child": null,
    "dependent_parent": null,
    "min_value": null,
    "max_value": null,
    "options": [],
    "regex": null,
    "is_in_progress": false,
    "is_single_valued": false,
    "primary_dp_list": [],
    "sub_data_point_list": [
    ]
}


const DpFormFields = ({addDatapoint}) => {
    const {datapoints} = useContext(AppContext)
    const [modalPath, setModalPath] = useState([]);
    const [openModal, setOpenModal] = useState(false)
    const [subDpFormData, setSubDpFormData] = useState(mainInitialData);

    const dpKeys = Object.keys(datapoints || {})


    const dataMap = [
        {name: 'name', label: 'Name', size: '12', fieldType: formFieldTypes.text, value: '', required: true},
        {name: 'label', label: 'Label', size: '12', fieldType: formFieldTypes.text, value: '', required: true},
        {
            name: 'description',
            label: 'Description',
            size: '12',
            fieldType: formFieldTypes.text,
            value: '',
            required: true
        },
        {
            name: 'type',
            label: 'Type',
            size: '12',
            fieldType: formFieldTypes.enum,
            options: dpTypes,
            value: '',
            required: true
        },
        {name: 'options', label: 'Options', size: '12', fieldType: formFieldTypes.multipleStirng, value: ""},
        {name: 'min_value', label: 'Min value', size: '6', fieldType: formFieldTypes.number, value: ""},
        {name: 'max_value', label: 'Max value', size: '6', fieldType: formFieldTypes.number, value: ""},
        {name: 'regex', label: 'Regex', size: '12', fieldType: formFieldTypes.text, value: ""},
        {
            name: 'dependent_parent',
            label: 'Dependent parent',
            size: '12',
            fieldType: formFieldTypes.dpFinder,
            value: "",
            options: dpKeys
        },
        {
            name: 'dependent_child',
            label: 'Dependent child',
            size: '12',
            fieldType: formFieldTypes.dpFinder,
            value: "",
            options: dpKeys
        },
        {name: 'primary_dp_list', label: 'Primary datapoint list', size: '6'},
        {name: 'sub_data_point_list', label: 'Sub datapoint list', size: '6'},
        {name: 'is_in_progress', label: 'Is in progress', size: '12', fieldType: formFieldTypes.checkbox, value: ""},
        {
            name: 'is_single_valued',
            label: 'Is single valued',
            size: '12',
            fieldType: formFieldTypes.checkbox,
            value: ""
        },
    ]

    const [dpFormData, setDpFormData] = useState(initialData);

    const handleFieldValueChange = (fieldName, value) => {
        if (fieldName === 'name') {
            value = handleize(value);
        }
        setDpFormData((prevState) => ({
            ...prevState,
            [fieldName]: value,
        }));
    };
    console.log(subDpFormData)
    const handleSubDpFieldValueChange = (fieldName, value) => {
        if (fieldName === 'name') {
            value = handleize(value);
        }
        setSubDpFormData((prevState) => ({
            ...prevState,
            [fieldName]: value,
        }));

    };

    const handleOpenModal = (path) => {
        setModalPath(path);
        setOpenModal(true);
        // setSubDpFormData({...mainInitialData})

    };

    const handleCloseModal = () => {
        setModalPath([]);
        // setSubDpFormData({...mainInitialData})
        setOpenModal(false);
    };

    const handleAddSubDataPoint = (e,newSubDataPoint) => {
        // e.preventDefault()
        console.log(newSubDataPoint,'clicked')
        const updatedFormData = {...dpFormData};
        // const newSubDataPoint = {...subDpFormData};

        let currentLevel = updatedFormData;
        let currentPath = modalPath.slice();

        while (currentPath.length >= 1) {
            const key = currentPath.shift();
            currentLevel = currentLevel.sub_data_point_list[key];
        }
        currentLevel.sub_data_point_list.push(newSubDataPoint)

        setDpFormData(updatedFormData);
        handleCloseModal();
    };
    const handleDeleteSubDataPoint = (pathToDelete) => {
        const updatedFormData = {...dpFormData};
        let currentLevel = updatedFormData;
        let currentPath = [...pathToDelete];

        while (currentPath.length > 1) {
            const key = currentPath.shift();
            currentLevel = currentLevel.sub_data_point_list[key];
        }

        const parentLevel = currentLevel;
        const indexToRemove = currentPath[0];

        if (parentLevel && parentLevel.sub_data_point_list) {
            parentLevel.sub_data_point_list.splice(indexToRemove, 1);
            setDpFormData(updatedFormData);
        }

        // handleCloseModal();
    };

    const renderSubDataPoints = (subDataPoints, path = []) => {
        return subDataPoints.map((subDp, index) => {
            const newPath = [...path, index];
            return (
                <div key={index}>
                    <Chip
                        label={subDp.name}
                        onClick={() => handleOpenModal(newPath)}
                        onDelete={() => handleDeleteSubDataPoint(newPath)}
                        deleteIcon={<Delete className='text-danger'/>}
                        variant="outlined"
                        className={`rounded w- d-flex justify-content-between ${
                            path.length > 0 ? 'ml-2' : ''
                        }`}
                    />
                    {subDp.sub_data_point_list.length > 0 && (
                        <div className={`pl-4 ${path.length > 0 ? 'ml-2' : ''}`}>
                            {renderSubDataPoints(subDp.sub_data_point_list, newPath)}
                        </div>
                    )}
                </div>
            );
        });
    };

    return (
        <Fragment>
            <Card className='bg-light'>
                <CardHeader title={dpFormData['name'] || "New Datapoint's name"}/>
                <CardContent>

                    <Grid container spacing={3} className='mb-5'>
                        {dataMap.map((field, i) => {
                            if (field.fieldType) {
                                return (
                                    <Grid item xs={parseInt(field.size)} key={i}>
                                        <Input
                                            name={field.name}
                                            label={field.label}
                                            value={dpFormData[field.name] || ''}
                                            type={field.fieldType}
                                            onChange={(value) => handleFieldValueChange(field.name, value)}
                                            options={field.options}
                                            required={field.required}
                                        />

                                    </Grid>
                                )
                            } else return (
                                <Grid item xs={parseInt(field.size)} key={i}>
                                    <Card>
                                        <CardContent>
                                            <div className="d-flex justify-content-between align-items-center mb-2">
                                                <p className='text-20 mb-2'>{field.label}</p>
                                                <Button variant="outlined" startIcon={<Add/>}
                                                        onClick={() => handleOpenModal([])}>
                                                    Add
                                                </Button>
                                            </div>

                                            <div className="pl-4">
                                                {renderSubDataPoints(dpFormData.sub_data_point_list)}
                                            </div>

                                        </CardContent>
                                    </Card>
                                </Grid>
                            )
                        })}
                    </Grid>


                    <CardActions className='px-3 d-flex justify-content-end'>
                        <Button type="submit" variant='contained' color='primary'>Save</Button>
                    </CardActions>

                    <CustomModal open={openModal} handleClose={handleCloseModal}>
                        <CardHeader title="Create SubDataPoint" className='tkdc-primary text-white'/>
                        {console.log(modalPath)}
                        <Card className='bg-light'>
                            <CardHeader title={subDpFormData['name'] || "New SubDatapoint's name"}/>
                            <CardContent>

                                <Grid container spacing={3} className='mb-5'>
                                    {dataMap.map((field, i) => {
                                        if (field.fieldType) {


                                            return (
                                                <Grid item xs={parseInt(field.size)} key={i}>
                                                    <Input
                                                        name={field.name}
                                                        label={field.label}
                                                        value={subDpFormData[field.name] || ''}
                                                        type={field.fieldType}
                                                        onChange={(value) => handleSubDpFieldValueChange(field.name, value)}
                                                        options={field.options}
                                                        required={field.required}
                                                    />
                                                </Grid>
                                            )
                                        } else return (
                                            <Grid item xs={parseInt(field.size)} key={i}>
                                                <Card>
                                                    <CardContent>
                                                        <div
                                                            className="d-flex justify-content-between align-items-center mb-2">
                                                            <p className='text-20 mb-2'>{field.label}</p>
                                                        </div>
                                                        <div className="pl-4">

                                                        </div>
                                                    </CardContent>
                                                </Card>
                                            </Grid>
                                        )
                                    })}
                                </Grid>
                                <CardActions className='px-3 d-flex justify-content-end'>
                                    <Button type='button' variant='contained' color='primary'
                                            onClick={(e) => handleAddSubDataPoint(e,subDpFormData)}>Save</Button>
                                </CardActions>


                            </CardContent>
                        </Card>
                    </CustomModal>

                </CardContent>

            </Card>

        </Fragment>
    )
}

export default withAppContext(DpFormFields)

0 Answers0