Reputation: 2535
I have a form using react-hooks-form, and I made some components for me, like textbox, text area, select, ... These are controlled components all. Now in my form I am using Yup for validation, and there is a point when it is not working. In my form I have a dynamic input type (queryParam) that changes depending on the value of the group select, and it can be a textbox or a select. When group is 1, there is no needed for queryParam, but if the value of the group is greater then 1 then the filed is shown and I need the value form queryParam input, but it's not validating, I can't press the button. The queryParam can me a text from a text box or a number as string from select.
My validation schema:
import * as Yup from "yup";
export const validationSchema = Yup.object().shape
({
text: Yup
.string()
.required()
.max(2048, "Az üzenet szövege túl hosszú,"),
groupID: Yup
.number()
.required(),
queryParam: Yup
.string()
.when("groupID",
{
/*** THIS PART NOT WORKING ***/
is: (groupID: number) => groupID > 1,
then: Yup.mixed()
.required("Kötelező mező.")
}),
isVoteType: Yup
.boolean(),
positiveAnswer: Yup
.string()
.when("isVoteType",
{
is: (isVoteType: boolean) => isVoteType,
then: Yup.string()
.required("Kötelező mező.")
}),
negativeAnswer: Yup
.string()
.when("isVoteType",
{
is: (isVoteType: boolean) => isVoteType,
then: Yup.string()
.required("Kötelező mező.")
})
});
My component with the form:
import React, { useEffect, useState } from "react";
import { IonButton, IonCol, IonContent, IonGrid, IonPage, IonRow } from "@ionic/react";
import Footer from "src/pages/shared/footer/footer";
import Header from "src/pages/shared/header/header";
import { IMessageRequest } from "./../../../../modell/request/IMessageRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/dist/yup";
import { validationSchema } from "./validation";
import { GroupsSelectList } from "./../../../../pages/shared/selectLists/GroupsSelectList";
import { ISelectListItem } from "./../../../../modell/common/ISelectListItem";
import HookFormTextArea from "./../../../../library/HookForm/Components/hookFomTextArea";
import { WebAPI } from "src/service/webAPI";
import HookFormCheckbox from "./../../../../library/HookForm/Components/hookFormCheckbox";
import HookFormTextBox from "./../../../../library/HookForm/Components/hookFomTextBox";
import { DegreeSelectList } from "./../../../../pages/shared/selectLists/DegreeSelectList";
import { SexesSelectList } from "./../../../../pages/shared/selectLists/SexesSelectList";
import { CountriesSelectList } from "src/pages/shared/selectLists/CountriesSelectList";
const NewMessagePage: React.FC = () =>
{
const[groups, setGroups] = useState<ISelectListItem[]>([]);
const[selectedGroup, setSelectedGroup] = useState<ISelectListItem>();
const[degrees, setDegrees] = useState<ISelectListItem[]>([]);
const[sexes, setSexes] = useState<ISelectListItem[]>([]);
const[countries, setCountries] = useState<ISelectListItem[]>([]);
const[isVote, setIsVote] = useState<boolean>(false);
useEffect(() =>
{
const fetch = async (): Promise<void> =>
{
await WebAPI.Common.groups()
.then( (data: ISelectListItem[]) => setGroups(data));
await WebAPI.Common.degrees()
.then( (data: ISelectListItem[]) => setDegrees(data));
await WebAPI.Common.sexes()
.then( (data: ISelectListItem[]) => setSexes(data));
await WebAPI.Common.countries()
.then( (data: ISelectListItem[]) => setCountries(data));
}
fetch();
}, []);
const { control, handleSubmit, errors, register, formState } = useForm<IMessageRequest>
({
mode: "onChange",
resolver: yupResolver(validationSchema)
});
const onSubmit = async (data: IMessageRequest): Promise<void> =>
{
data.negativeAnswer = data.negativeAnswer === "" ? undefined : data.negativeAnswer;
data.positiveAnswer = data.positiveAnswer === "" ? undefined : data.positiveAnswer;
console.log({...data});
}
const QueryParamElement = (): JSX.Element | null =>
{
switch (selectedGroup?.id)
{
/* country */
case 2:
return <CountriesSelectList
name="queryParam"
label="Cél ország neve"
data={countries}
placeholder="Kérem válasszon"
displayMember={(item: ISelectListItem) => item.name}
valueMember={(item: ISelectListItem) => item?.id.toString()}
control={control}
errors={errors} />
/* city */
case 3:
return <HookFormTextBox
name="queryParam"
label="Cél város neve"
type="text"
control={control}
errors={errors} />;
/* degree */
case 4:
return <DegreeSelectList
name="queryParam"
label="Válassza ki az iskola végzettséget"
data={degrees}
placeholder="Kérem válasszon"
displayMember={(item: ISelectListItem) => item.name}
valueMember={(item: ISelectListItem) => item?.id.toString()}
control={control}
errors={errors}
reference={register} />;
/* sex */
case 5:
return <SexesSelectList
name="queryParam"
label="Válassza ki a nemet"
data={sexes}
placeholder="Kérem válasszon"
displayMember={(item: ISelectListItem) => item.name}
valueMember={(item: ISelectListItem) => item?.id.toString()}
control={control}
errors={errors}
reference={register} />;
default: return null;
}
}
return (
<IonPage>
<Header text="Új Üzenet Létrehozása" />
<IonContent fullscreen>
<form onSubmit={handleSubmit((data: IMessageRequest) => onSubmit(data))}>
<IonGrid>
<IonRow>
<IonCol size="12" sizeMd={QueryParamElement() === null ? "12" : "6"}>
<GroupsSelectList
name="groupID"
label="Csoport"
data={groups}
placeholder="Kérem válasszon"
displayMember={(item: ISelectListItem) => item.name}
valueMember={(item: ISelectListItem) => item?.id.toString()}
onChange={ (item: ISelectListItem) => setSelectedGroup(item)}
control={control}
errors={errors}
reference={register} />
</IonCol>
<IonCol size="12" sizeMd="6">
{QueryParamElement()}
</IonCol>
</IonRow>
<IonRow>
<HookFormTextArea
name="text"
label="Üzenet szövege"
autoGrow={true}
fullWidth={true}
control={control}
errors={errors} />
</IonRow>
<IonRow>
<IonCol size="12" sizeMd="4">
<HookFormCheckbox
name="isVote"
label="Szavazás"
onChange={(e: boolean) =>
{
setIsVote(e);
console.log(e);
}}
checked={isVote}
control={control}
errors={errors} />
</IonCol>
<IonCol size="12" sizeMd="4">
<HookFormTextBox
name="positiveAnswer"
label="Pozitív válasz szövege"
type="text"
disabled={!isVote}
control={control}
errors={errors} />
</IonCol>
<IonCol size="12" sizeMd="4">
<HookFormTextBox
name="negativeAnswer"
label="Negatív válasz szövege"
type="text"
disabled={!isVote}
control={control}
errors={errors} />
</IonCol>
</IonRow>
<IonRow>
</IonRow>
<IonRow>
<IonCol>
<IonButton expand="block" type="submit" className="ion-margin-top"
disabled={formState.isValid === false}>
KÜLDÉS
</IonButton>
</IonCol>
</IonRow>
</IonGrid>
</form>
</IonContent>
<Footer />
</IonPage>
);
}
export default NewMessagePage;
Upvotes: 0
Views: 15765
Reputation: 11
Try using transform(). It helped me with case when value was an empty string.
yup.mixed().transform((v) => (!v ? undefined : v)).required('Field is required')
Upvotes: 1
Reputation: 2535
Here is what I did at the end:
import * as Yup from "yup";
export const validationSchema = Yup.object().shape
({
text: Yup
.string()
.required("Kötelező mező.")
.max(2048, "Az üzenet szövege túl hosszú,"),
groupID: Yup
.number()
.min(1, "Kötelező mező.")
.required("Kötelező mező."),
queryParam: Yup
.mixed()
.when("groupID",
{
is: (groupID: number) => groupID > 1,
then: Yup.lazy( (value: any) =>
{
console.log("value: ", value);
if (value === -1 || value === "-1" || value === "" || value === undefined || value === null)
{
switch (typeof(value))
{
case "string": return Yup.string()
.required("Kötelező mező.");
case "number": return Yup.number()
.min(1, "Kötelező mező.");
}
}
return Yup.mixed()
.notRequired()
})
}),
isVoteType: Yup
.boolean(),
positiveAnswer: Yup
.string()
.when("isVoteType",
{
is: (isVoteType: boolean) => isVoteType,
then: Yup.string()
.required("Kötelező mező.")
}),
negativeAnswer: Yup
.string()
.when("isVoteType",
{
is: (isVoteType: boolean) => isVoteType,
then: Yup.string()
.required("Kötelező mező.")
})
});
Upvotes: 1