How to populate a ref and register file input in react-hook-form simultaenously?

Viewed 36

I have a custom component built using chakraUI which I want to use as a file input for react-hook forms.

Im using chakraUI to call click event on hidden html to select files.

When using this component, I noticed react-hook-form cannot get the file value from the html embedded.

  <Controller
          name={name}
          control={control}
          defaultValue=""
          render={({ onChange, name, value }) => {
            return (
              <InputGroup>
                <InputLeftElement pointerEvents="none">
                  <Icon as={FiFile} />
                </InputLeftElement>
                <input
                  name={name}
                  type="file"
                  onChange={ (e) => onChange(e.target.files[0]) }
                  accept={acceptedFileTypes}
                  //ref={inputRef}
                  //ref={ (el)=> { register(el) ; inputRef.current=el;}}
                  ref={(event) => {
                    register(event, name);
                   inputRef.current = event;
                  }}
                  
                  style={{ display: "none" }}
                />
                <Input
                  placeholder={placeholder || "Your file ..."}
                  onClick={() => inputRef.current.click()}
                  // onChange={(e) => {}}
                 // onChange={console.log(value)}
                  readOnly={true}
                  value={(value && value.name) || ""}
                />
              </InputGroup>
            );
          }}
        />

The component is exported from a file and implemented as :

import React, { useState, useRef } from "react";
import {

  Button,
  ButtonGroup
} from "@chakra-ui/react";
import { useController, useForm, Controller } from "react-hook-form";
import UploadUnit from "./UploadUnit";
import updateAction from "./updateAction";
import storage from "./fireBaseConfig.js"

export const FileUpload = ({
  name,

}) => {
  const inputRef = useRef();
  const { register,handleSubmit,errors,getValues,setValue,watch,control,ref } = useForm();


  const onSubmit = (data) => {



    console.log("List:" + data.testing[0].name ); // this correctly returns file name
    console.log("List:" + data.trn[0].name ); // this returns undefined
    
    const storageRef = storage;
   //const fileRef = storageRef.child( data.files[0].name );

    //fileRef.put(data.files[0]).then( () => { console.log("uploaded a file") })
   

  };

  register( { name: "trn", type:"custom"})

  return (
    <>
      <form onSubmit={ handleSubmit(onSubmit) }>
        <br />

        <div>
          <input type="file" name="testing" ref={register} />
        </div>
          <br></br>
        <div>
          <UploadUnit name="trn"  ></UploadUnit>
        </div>
        <br />

        <br />
        <div>
          <UploadUnit name="nis"  ></UploadUnit>
        </div>
        <br />

        <br />
        <div></div>
        <br />
        <br></br>
        <ButtonGroup spacing={4}>
          <Button loadingText="Submitting"  type="submit">
            Save Progress
          </Button>
          <Button variant="outline">
            Next
          </Button>
        </ButtonGroup>
      </form>
    </>
  );
};

export default FileUpload;

I have tried :

  ref={(event) => {
                   register(event, name);
                   inputRef.current = event;
                  }}

However when I try the above solution I get the following errors after I select file:

Uncaught TypeError: Failed to set the 'files' property on 'HTMLInputElement': Failed to convert value to 'FileList'

and:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'name')

1 Answers

The solution was to use

                    ref={(el) => {
                      inputRef.current = el;
                      register(el);
                    }}

the inputRef must be assigned before the register value or else it throws an error.

Working example posted here: Code Sandbox

Related