Open erwin-gapai opened 2 weeks ago
You are passing the props to FormInput but you are not using it. Since you are using typescript lets re-write the code in strong type kinda way: Try this instead:
LoginForm
'use client'
import { Form } from '@/components/ui/form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { FormInput } from './FormInput'
import { Button } from '@/components/ui/button'
export const LoginSchema = z.object({
email: z.string(),
password: z.string(),
})
const LoginForm = () => {
const form = useForm<z.infer<typeof LoginSchema>>({
resolver: zodResolver(LoginSchema),
defaultValues: {
email: '',
password: '',
},
})
const onSubmit = (data: z.infer<typeof LoginSchema>) => {
//Handle submition result
console.log(data)
}
return (
<div className="p-16 ">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormInput
control={form.control}
name="email"
label="Email"
type="text"
placeholder="Enter your email"
id="email"
required
/>
<FormInput
control={form.control}
name="password"
label="Password"
type="password"
placeholder="Enter your Password"
id="password"
required
/>
<Button type="submit">Login</Button>
</form>
</Form>
</div>
)
}
export default LoginForm
import { FormControl, FormField, FormItem } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { cn } from '@/lib/utils'
import { Control } from 'react-hook-form'
import { LoginSchema } from './LoginForm'
import { z } from 'zod'
interface FormInputProps {
control: Control<z.infer<typeof LoginSchema>>
name: keyof z.infer<typeof LoginSchema>
type: string
required?: boolean
id?: string
label?: string
placeholder?: string
hasError?: boolean
}
export const FormInput = (props: FormInputProps) => {
const { control, name, type, hasError, placeholder, id, required } = props
return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem>
<FormControl>
<Input
{...field}
id={id}
required={required}
//variant={hasError ? "danger" : "default"} assuming you have configured variants
className={cn(hasError && 'border-red-500 ring-red-500')} // if you havent configured the variant you can use classes name
type={type}
placeholder={placeholder}
/>
</FormControl>
</FormItem>
)}
/>
)
}
This will insure your props is passed and is being used correctly, here is a screenshot for when submitting the form:
I hope thats help!
@OmarAljoundi Hey Omar, my current code resembles yours closely. The onSubmit function worked perfectly, but there were some issues with certain props like onChange and onBlur not being forwarded.
I ended up made updates to the FormInput component as shown below:
"use client";
import { Control } from "react-hook-form";
import { Input, InputProps } from "@/components/ui/input";
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage
} from "@/components/ui/form";
import { ChangeEvent, FocusEvent, ReactNode } from "react";
export interface FormInputProps extends InputProps {
label: string;
helper?: string | ReactNode;
control?: Control<any>;
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
}
const FormInput = ({
label,
name,
type,
placeholder,
control,
required,
helper,
onChange,
onBlur,
onFocus
}: FormInputProps) => {
const fieldState = control?.getFieldState(`${name}`);
const hasError = !!fieldState?.error;
const hasErrorMessage = !!fieldState?.error?.message;
return (
<FormField
control={control}
name={name || ""}
render={({ field }) => (
<FormItem>
<FormLabel>
{label}
{required && <span className="text-danger-500">*</span>}
</FormLabel>
<FormControl>
<Input
variant={hasError ? "danger" : "default"}
type={type}
placeholder={placeholder}
{...field}
onChange={(event) => {
if (onChange) onChange(event);
field.onChange(event);
}}
onBlur={(event) => {
if (onBlur) onBlur(event);
field.onBlur();
}}
onFocus={(event) => {
if (onFocus) onFocus(event);
}}
/>
</FormControl>
{!hasErrorMessage && <FormDescription>{helper}</FormDescription>}
<FormMessage className="text-xs font-normal" />
</FormItem>
)}
/>
);
};
export default FormInput;
FYI, I utilized control?: Control<any>;
because of the component's reusability concern.
Thanks
Describe the bug
Hi,
In my project, I created a wrapper component that consists of FormField along with Input component. The issue is, props that I set in the custom component is not being forwarded to the wrapper component, such as the onChange method.
LoginForm.tsx
FormInput.tsx
Anyone knows the issue? Thanks
Affected component/components
Input
How to reproduce
Codesandbox/StackBlitz link
No response
Logs
No response
System Info
Before submitting