javascriptreactjsremixremix.run

How to get fetcher.Form values in remix


Im using useFetcher() to create a form via <fetcher.Form>. I have several input fields throughout the form, but I do not want the form to be submitted when the user hits the enter key. To do so, on form submission I have a form handler that calls e.preventDefault(). I want the form to be submitted via an explicit user action (clicking a Save button. I assumed that in order to submit the form manually I would call fetcher.submit(), but I need the forms values to do so, but the fetcher hook doesnt seem to provide a way of getting them. I cant figure out an easy way to get the forms values to do the submission without creating controlled input fields, which defeats the whole purpose of using <fetcher.Form>. Is the solution to just create a whole form with controlled inputs or am I missing something?

const fetcher = useFetcher():

function submitHandler(e: FormEvent) {
    e.preventDefault();
}

function realSubmit(){
    // let formData = fetcher.data;
    let formData = ""; // how do I get the form data??

    fetcher.submit(formData, fetcher.formAction);
}

return(
    <fetcher.Form action="/some/route" onSubmit={submitHandler} method="post">
        <input name="input1" type="text"/>
        <input name="input2" type="text"/>
        <input name="input3" type="text"/>
     
        <button type="submit" onClick={realSubmit}>Save</button>
    </fetcher.Form>
);

Any help would be greatly appreciated!


Solution

  • The simplest is to create a form ref. Then you can create a FormData object from the ref and submit it.

    export default function Index() {
      const fetcher = useFetcher();
      const formRef = useRef<HTMLFormElement>(null);
      function submitHandler(e: FormEvent) {
        e.preventDefault();
      }
    
      function realSubmit() {    
        const formData = new FormData(formRef.current!);
        // modify formData here
        formData.set("message", "hello world")
        fetcher.submit(formData);
      }
    
      return (
        <fetcher.Form ref={formRef} onSubmit={submitHandler} method="post">
          <input name="input1" type="text" />
          <input name="input2" type="text" />
          <input name="input3" type="text" />
    
          <button type="submit" onClick={realSubmit}>
            Save
          </button>
        </fetcher.Form>
      );
    }
    

    EDIT: Another option is to keep the regular submit handler.

    export default function Index() {
      const fetcher = useFetcher();
    
      function submitHandler(e: FormEvent) {
        // get formData from currentTarget (form)
        const formData = new FormData(e.currentTarget);
    
        // modify formData here
        formData.set("message", "hello world")
    
        // submit formData using fetcher
        fetcher.submit(formData);
    
        // prevent default form submit
        e.preventDefault();
      }
    
      return (
        <fetcher.Form onSubmit={submitHandler} method="post">
          <input name="input1" type="text" />
          <input name="input2" type="text" />
          <input name="input3" type="text" />
    
          <button type="submit">
            Save
          </button>
        </fetcher.Form>
      );
    }