0

Im using https://ui.shadcn.com/docs/components/form components for my nextjs13 app. I want to either dynamically set the input fields value to the edited goal or when I click the "add" button to type a value in the field.

Currently this works fine except the zod validation doesnt know about my form values? I get "Required" as an error message under my input field. How can I let zod know the form values when using value={} and onChange={} props in chadcn Input fields?enter image description here

enter image description here

'use client';

import React, { useEffect } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import * as z from 'zod';

import { Button } from '@/components/ui/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { toast } from '@/components/ui/use-toast';
import ButtonLoading from './ui/ButtonLoading';
import { useState } from 'react';
import { GoalType } from '@/types/goal';

interface GoalDayFormProps {
    editedGoal: GoalType | null;
    setEditedGoal: React.Dispatch<React.SetStateAction<GoalType | null>>;
}

const GoalDayForm = ({ editedGoal, setEditedGoal }: GoalDayFormProps) => {
    const [loading, setLoading] = useState(false);
    const [addingGoal, setAddingGoal] = useState(false);
    const [newGoalText, setNewGoalText] = useState('');

    useEffect(() => {
        if (editedGoal) {
            setAddingGoal(false);
        }
    }, [editedGoal]);

    const FormSchema = z.object({
        goal: z.string().min(1, {
            message: 'The goal field cannot be empty.',
        }),
    });

    const form = useForm<z.infer<typeof FormSchema>>({
        resolver: zodResolver(FormSchema),
    });

    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        if (editedGoal) {
            setEditedGoal((prev: any) => ({ ...prev, text: e.target.value }));
        }

        setNewGoalText(e.target.value);
    };

    function onSubmit(data: z.infer<typeof FormSchema>) {
        console.log(data);

        toast({
            title: 'You submitted the following values:',
            description: (
                <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
                    <code className="text-white">{JSON.stringify(data, null, 2)}</code>
                </pre>
            ),
        });

        if (editedGoal) {
            setEditedGoal(null);
        }
    }

    return (
        <Form {...form}>
            <form onSubmit={form.handleSubmit(onSubmit)} className="mt-[1.5rem] w-full space-y-4">
                {(addingGoal || editedGoal) && (
                    <FormField
                        control={form.control}
                        name="goal"
                        render={({ field }) => (
                            <FormItem>
                                <FormControl>
                                    <Input
                                        placeholder="Goal description"
                                        {...field}
                                        value={editedGoal ? editedGoal.text : newGoalText}
                                        onChange={(e) => handleInputChange(e)}
                                    />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                )}

                <div className="flex gap-4">
                    {addingGoal && (
                        <>
                            <Button
                                variant="ghost"
                                disabled={loading}
                                onClick={() => setAddingGoal(false)}
                            >
                                Cancel
                            </Button>
                            <ButtonLoading loading={loading} type="submit">
                                Add goal
                            </ButtonLoading>
                        </>
                    )}

                    {editedGoal && (
                        <>
                            <Button
                                variant="ghost"
                                disabled={loading}
                                onClick={() => setEditedGoal(null)}
                            >
                                Cancel
                            </Button>
                            <ButtonLoading loading={loading} type="submit">
                                Edit goal
                            </ButtonLoading>
                        </>
                    )}

                    {!addingGoal && !editedGoal && (
                        <Button onClick={() => setAddingGoal(true)}>New Goal</Button>
                    )}
                </div>
            </form>
        </Form>
    );
};

export default GoalDayForm;
0mppu
  • 25
  • 1
  • 4

0 Answers0