Is there a way of transforming what is sent by useForm?

I want to use the useForm hook but I want to transform the values it sends to the backend, I can't seem to see anything in the documentation but just asking here to confirm if I've missed something obvious. To give an example, lets say I have a form which accepts a title and description. Before this gets sent to the backend I would like to do some pre-processing on the 'title' parameter without it reflecting in the form. Is there a way of achieving this?
8 Replies
kapa.ai
kapa.ai4mo ago
Hi @Plornt. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, there is a way to modify the form data before it is sent to the API using the useForm hook in Refine. You can achieve this by defining a custom handler function that modifies the data before it is submitted. Here is an example of how you can do this:
import { useForm } from "@refinedev/react-hook-form";
import React from "react";
import { FieldValues } from "react-hook-form";

export const UserCreate: React.FC = () => {
const {
refineCore: { onFinish },
register,
handleSubmit,
} = useForm();

const onFinishHandler = (data: FieldValues) => {
onFinish({
fullName: `${data.name} ${data.surname}`,
});
};

return (
<form onSubmit={handleSubmit(onFinishHandler)}>
<label>Name: </label>
<input {...register("name")} />
<br />

<label>Surname: </label>
<input {...register("surname")} />
<br />

<button type="submit">Submit</button>
</form>
);
};
import { useForm } from "@refinedev/react-hook-form";
import React from "react";
import { FieldValues } from "react-hook-form";

export const UserCreate: React.FC = () => {
const {
refineCore: { onFinish },
register,
handleSubmit,
} = useForm();

const onFinishHandler = (data: FieldValues) => {
onFinish({
fullName: `${data.name} ${data.surname}`,
});
};

return (
<form onSubmit={handleSubmit(onFinishHandler)}>
<label>Name: </label>
<input {...register("name")} />
<br />

<label>Surname: </label>
<input {...register("surname")} />
<br />

<button type="submit">Submit</button>
</form>
);
};
In this example, the onFinishHandler function is used to combine the name and surname fields into a fullName field before the data is submitted to the API. You can modify this function to preprocess the title parameter as per your requirements. For more information, you can check out the Refine documentation (https://refine.dev/docs/packages/react-hook-form/use-form#how-can-i-change-the-form-data-before-submitting-it-to-the-api). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@383377580524306465> kapa.ai is still learning and improving, please let us know how it did by reacting below
metropolitan-bronze
metropolitan-bronze4mo ago
@kapa.ai additional question, if using the resolver option of react-hook-form with useForm and the 'transformed' schema is different to what the resolver would accept then this would pose a problem as the resolver property uses the 3rd generic argument of the useForm hook (which is the same type that onFinish uses). Is there any way around this?
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, you can handle this situation by using a separate type for the resolver and the transformed data. The useForm hook in Refine accepts three generic parameters: TData, TError, and TSubmitData. - TData is the type of the data returned by the get method of the dataProvider. - TError is the type of the error returned by the dataProvider. - TSubmitData is the type of the data sent to the dataProvider's create, update, or custom methods. You can use TSubmitData to define the type of the transformed data that you want to send to the API, and use TData for the resolver. Here is an example:
import { useForm } from "@refinedev/react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";

interface IFormValue {
name: string;
surname: string;
}

interface ITransformedValue {
fullName: string;
}

const schema = Yup.object().shape({
name: Yup.string().required(),
surname: Yup.string().required(),
});

const { control } = useForm<IFormValue, any, ITransformedValue>({
mode: "onChange",
resolver: yupResolver(schema),
});

const onFinishHandler = (data: IFormValue) => {
onFinish({
fullName: `${data.name} ${data.surname}`,
});
};
import { useForm } from "@refinedev/react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";

interface IFormValue {
name: string;
surname: string;
}

interface ITransformedValue {
fullName: string;
}

const schema = Yup.object().shape({
name: Yup.string().required(),
surname: Yup.string().required(),
});

const { control } = useForm<IFormValue, any, ITransformedValue>({
mode: "onChange",
resolver: yupResolver(schema),
});

const onFinishHandler = (data: IFormValue) => {
onFinish({
fullName: `${data.name} ${data.surname}`,
});
};
In this example, IFormValue is used for the resolver and ITransformedValue is used for the transformed data. This way, you can ensure that the resolver validates the form data correctly, and the transformed data is sent to the API in the desired format. For more information, you can check out the Refine documentation (https://refine.dev/docs/packages/react-hook-form/use-form#how-can-i-change-the-form-data-before-submitting-it-to-the-api). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@383377580524306465> kapa.ai is still learning and improving, please let us know how it did by reacting below
metropolitan-bronze
metropolitan-bronze4mo ago
@kapa.ai Unfortunately that doesn't seem to actually be the case, the resolver property uses the TVariables type which is the 3rd type argument and the return onFinish property also uses TVariables
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- I apologize for the confusion. You're correct that both the resolver and onFinish use the TVariables type, which is the third generic argument of the useForm hook. This means that the data validated by the resolver and the data sent to the API need to be of the same type. However, you can still transform the data inside the onFinish function before it's sent to the API. The key is to ensure that the transformed data still conforms to the TVariables type. If the transformed data doesn't match the TVariables type, TypeScript will throw an error. Here's an example:
import { useForm } from "@refinedev/react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";

interface IFormValue {
name: string;
surname: string;
}

const schema = Yup.object().shape({
name: Yup.string().required(),
surname: Yup.string().required(),
});

const { control, onFinish } = useForm<IFormValue, any, IFormValue>({
mode: "onChange",
resolver: yupResolver(schema),
});

const onFinishHandler = (data: IFormValue) => {
onFinish({
name: `${data.name} transformed`,
surname: `${data.surname} transformed`,
});
};
import { useForm } from "@refinedev/react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";

interface IFormValue {
name: string;
surname: string;
}

const schema = Yup.object().shape({
name: Yup.string().required(),
surname: Yup.string().required(),
});

const { control, onFinish } = useForm<IFormValue, any, IFormValue>({
mode: "onChange",
resolver: yupResolver(schema),
});

const onFinishHandler = (data: IFormValue) => {
onFinish({
name: `${data.name} transformed`,
surname: `${data.surname} transformed`,
});
};
In this example, the onFinishHandler function transforms the name and surname fields by appending the string " transformed" to them. The transformed data still conforms to the IFormValue type, so TypeScript doesn't throw an error. I hope this helps! If you have any other questions, feel free to ask. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@383377580524306465> kapa.ai is still learning and improving, please let us know how it did by reacting below