Evgeny Alekseev
Evgeny Alekseev

Reputation: 185

How to call child submit method from another child component

Im trying to solve this for 2 days but cant. How to call onSubmit method in CreateProject component when onApply function called in ModalContent component with Typescript and react-hook-form. The idea: when I clicked button in ModalContent it should call react-hook-form onSumbit method in CreateProject. Then CreateProject calls onSubmit in parent component of these two childs.

Or maybe the idea of such component structure is wrong?

Thanks everyone for any answers.

Parent component:

import { ModalBody } from '../../components/modals'
import useCreateProject from '../../api/hooks/createProject'

export default function New(): JSX.Element {
  const [modalVisible, setModalVisible] = React.useState(true)

  const onSubmit = useCreateProject((data) => {
    const { createProject } = data.data.data
    console.log(data)
  })

  const onApply = () => {
    console.log(123)
  }

  return (
    <ModalContent
      name={'Create project'}
      visible={modalVisible}
      onApply={onApply}
      onCancel={() => setModalVisible(false)}
    >
      <ModalBody>
        <CreateProject onSubmit={onSubmit.mutate} />
      </ModalBody>
    </ModalContent>
  )
}

Child component

import React from 'react'
import Input from '../Inputs/Input'
import Textarea from '../Inputs/Textarea'
import FileUploader from '../uploader/FileUploader'
import Tasks from '../forms/Tasks'
import { useForm } from 'react-hook-form'
import {
  draftBudgetMaxLength,
  projectNameMaxLength,
  descriptionMaxLength,
} from '../../constants/createProjectModal'
import ButtonSecondary from '../buttons/ButtonSecondary'

export interface IModalInputs {
  create_project_name: string
}

export interface ICreateProjectProps {
  onSubmit: (values: IModalInputs) => void
}

const СreateProject: React.FC<ICreateProjectProps> = ({
  onSubmit,
}): React.ReactElement => {
  const {
    register,
    getValues,
    control,
    handleSubmit,
    formState: { errors },
  } = useForm<IModalInputs>()

  return (
    <>
      <form onSubmit={handleSubmit(() => onSubmit(getValues()))}>
        <div className="p-4">
          <div className="flex flex-col -m-1.5">
            <div className="m-1.5">
              <Input
                type="text"
                label="Project name"
                name="create_project_name"
                register={register}
                error={errors.create_project_name}
                options={{
                  required: true,
                  maxLength: projectNameMaxLength,
                }}
              />
            </div>
          </div>
        </div>
      </form>
    </>
  )
}

export default СreateProject

Child component with click event

import React from 'react'
import Image from 'next/image'
import close from '../../assets/close.svg'
import ButtonSecondary from '../buttons/ButtonSecondary'

interface IModalContentProps {
  children: React.ReactElement
  onApply?: () => void
  visible: boolean
  buttonName?: string
}

const ModalContent: React.FC<IModalContentProps> = ({
  name,
  children,
  visible,
  onCancel,
  onApply,
  buttonName,
}) => {
  return (
    <>
      {visible && (
         <div className="flex p-4 space-x-2 justify-end">
            {children}
            <ButtonSecondary
                    click={onApply}
                    type={'submit'}
                    label={buttonName || 'Ok'}
                    id={buttonName}
                    shown={true}
                    styleClass="styleClass"
                    paddingClass="py-2 py-2 pr-4 pl-2"

            />
         </div>      
      )}
    </>
  )
}

export default ModalContent

Upvotes: 0

Views: 468

Answers (1)

Evgeny Alekseev
Evgeny Alekseev

Reputation: 185

The problem was resolved with useRef and useImperativeHandle hooks.

Parent:

export default function New(): JSX.Element {
  const [modalVisible, setModalVisible] = React.useState(true)
  const childRef = React.useRef<any>()

  const onSubmit = useCreateProject((data) => {
    const { createProject } = data.data.data
    console.log(data)
  })

  return (
    <ModalContent
      name={'Create project'}
      visible={modalVisible}
      onApply={() => childRef.current.SubmitForm()}
      onCancel={() => setModalVisible(false)}
    >
      <ModalBody>
        <CreateProject onSubmit={onSubmit.mutate} ref={childRef} />
      </ModalBody>
    </ModalContent>
  )
}

Child:

export interface IModalInputs {
  create_project_name: string
}

export interface ICreateProjectProps {
  onSubmit: (values: IModalInputs) => void
}

function CreateProject(props: ICreateProjectProps, ref) {
  const {
    register,
    getValues,
    control,
    handleSubmit,
    formState: { errors },
  } = useForm<IModalInputs>()

  useImperativeHandle(ref, () => ({
    SubmitForm() {
      handleSubmit(() => props.onSubmit(getValues()))()
    },
  }))

  return (
    <>
      <form ref={ref}>
        <div className="p-4">
          <div className="flex flex-col -m-1.5">
            <div className="m-1.5">
              <Input
                type="text"
                label="Project name"
                name="create_project_name"
                register={register}
                error={errors.create_project_name}
                options={{
                  required: true,
                  maxLength: projectNameMaxLength,
                }}
              />
            </div>
        
          </div>
        </div>
      </form>
    </>
  )
}

export default React.forwardRef(CreateProject)

Upvotes: 1

Related Questions