Comments (26)
Thank you for creating this issue. Currently this is possible with our pipeline feature. Below is an example:
import { object, number, enumType, custom, nullable } from 'valibot';
const YourSchema = object(
{
character: object({
type: enumType(['ninja', 'warrior', 'wizard']),
}),
shurikensAmount: nullable(number()),
},
[
custom(
(input) =>
input.character.type !== 'ninja' ||
typeof input.shurikensAmount === 'number',
'"shurikensAmount" is required if character type is "ninja"'
),
]
);
If you need this pipeline validation more than once, you can offload it to a separate function, which makes the schema cleaner.
import { object, number, enumType, nullable } from 'valibot';
import { checkShurikensAmount } from '~/validations';
const YourSchema = object(
{
character: object({
type: enumType(['ninja', 'warrior', 'wizard']),
}),
shurikensAmount: nullable(number()),
},
[checkShurikensAmount()]
);
As soon as I have some more time, I will investigate if a special API can make this even easier and type-safe.
from valibot.
Very cool 👍 thank you fabian!
from valibot.
thanks! will try it
it works i forgot to reverse the true to false !isBefore
from valibot.
You can use includes
validation instead of custom
with .includes
.
Thanks for the tip. Do you have time to investigate the problem or check with React Hook Form directly? My guess is that the problem is not with Valibot.
from valibot.
Hi, @fabian-hiller I've created a StackBlitz repro for this bug:
https://stackblitz.com/edit/stackblitz-starters-z8ytsk?file=src%2FApp.tsx
It's a form with 4 fields, of which 3 depend on the Required Input
field.
You can notice that every time the Required Input
triggers an onChange
and any of the other fields are undefined
, the web view freezes.
from valibot.
I have looked into it and can't figure out the problem. Can you create an issue at React Hook Form Resolvers? Feel free to link me. https://github.com/react-hook-form/resolvers
from valibot.
@demarchenac the internal implementation has changed with v0.13.0. Please read the release notes: https://github.com/fabian-hiller/valibot/releases/tag/v0.13.0
Oh ok, so I should use the issue
syntax instead of throwing a ValiError
error right?
from valibot.
Exactly. I will add the ability to specify the path soon. Thanks for your code examples regarding this.
from valibot.
v0.15.0 is now available.
from valibot.
@demarchenac feel free to let me know what you think about this.
from valibot.
@fabian-hiller Yeah I was just reading that issue!
from valibot.
Hi,
first thanks for this awesome lib!
how can i do this on the field startsAt i want to be ensure the field startsAt is always lower as the field endsAt isBefore is just from date-fns
export const createPollSchema = object(
{
question: string([minLength(3, 'Minimum 3 characters')]),
information: optional(string()),
id: optional(number()),
startsAt: coerce(date(), (input) => new Date(input as any)),
endsAt: coerce(date(), (input) => new Date(input as any)),
captcha: useDefault(boolean(), false),
pollOptions: array(pollOptions),
isClosed: useDefault(boolean(), false)
},
[
custom(
(input) => {
console.log(input);
return isBefore(input.startsAt, input.endsAt);
},
'startsAt is higher as endsAt'
)
]
);
thanks
from valibot.
@cannap thank you! If the if-condition is the right way around, your code looks good. I have tested the following code and it works.
import { coerce, custom, date, object, parse } from 'valibot';
const forceDate = (input: any) => new Date(input);
export const Schema = object(
{
startsAt: coerce(date(), forceDate),
endsAt: coerce(date(), forceDate),
},
[
custom(
(input) => input.startsAt < input.endsAt,
'The date of "endsAt" and must be after "startsAt".'
),
]
);
parse(Schema, { startsAt: 0, endsAt: 1000 }); // { startsAt: Date; endsAt: Date }
parse(Schema, { startsAt: 1000, endsAt: 0 }); // Throws error
from valibot.
yes but how can i add this function to the "startsAt" like: i just have access to the current value and not the whole object inside
startsAt: coerce(**custom(.....)** ,date(), forceDate),
//Pseude code
[
custom(
'startsAt', //would present the field where the custom validation is for or something
(input) => input.startsAt < input.endsAt,
'The date of "endsAt" and must be after "startsAt".'
),
]
because i work with veevalidation/valibot
https://github.com/logaretm/vee-validate/tree/main/packages/valibot
but i think there is no way to figure out which field is the custom function is for
//German
mein englisch suckt
Ich brauche einen Weg um der custom funktion zu sagen bei welchem Feld der Fehler raus kommen soll
from valibot.
I think that this is currently only possible through detours. However, I am aware of the problem and I will try to find a solution in the long run.
For example, I could try to provide the entire input in a second parameter at custom
, so that the validation can be done directly at startsAt
. However, at this point, the validation is not yet complete, so the input could be incorrect and I would have to type it as unknown
.
The second option would be to add to custom
the ability to specify which field is affected by an error, so that the error can be output in the correct place.
Until then, you can write your own validation function that throws a ValiError
with path information to startsAt
. Below is an example.
import { coerce, date, object, parse, ValiError } from 'valibot';
const forceDate = (input: any) => new Date(input);
export const Schema = object(
{
startsAt: coerce(date(), forceDate),
endsAt: coerce(date(), forceDate),
},
[
(input) => {
if (input.startsAt > input.endsAt) {
throw new ValiError([
{
reason: 'date',
validation: 'custom',
origin: 'value',
message: 'Invalid date',
input: input.startsAt,
path: [
{
schema: 'object',
input: input,
key: 'startsAt',
value: input.startsAt,
},
],
},
]);
}
return input;
},
]
);
parse(Schema, { startsAt: 0, endsAt: 1000 }); // { startsAt: Date; endsAt: Date }
parse(Schema, { startsAt: 1000, endsAt: 0 }); // Throws error
from valibot.
Hi, maybe this is unrelated but when I'm adding a custom
step to the PipeLine
of an object
using react-hook-form
with the valibotResolver
from @hookform/resolvers/valibot
, whenever I try to conditionally require a form field the view frozes.
Currently I've something like this:
const someStringList = ['a', 'b', 'c'];
export const vehicleUsageSchema = object(
{
controlField: withDefault(boolean(), false),
controlledField: nullish(string([custom((input) => someStringList.includes(input))]))
},
[
custom((input) => {
console.log(input);
return input.controlField? typeof input.controlledField === 'string' : true;
}, 'Some error message')
]
);
from valibot.
Hey, @fabian-hiller thanks for the suggestion maybe I didn't see the includes
while reading the methods. Also, I was reading through the issues and PR's for @hookform/resolvers
, but didn't find anything related. Could this be related to the fact that they're using valibot v0.12
and not valibot v0.13
, I'm asking since I saw that v0.13
introduces a breaking change right?
from valibot.
Actually, this should not be the problem. However, more people have the problem: #76 (comment)
from valibot.
I'll try researching a bit into this issue. Also, I don't think the includes
pipeline method would be a helpful replacement since my custom
checks if input
from the pipeline is included within the values of a given list of strings
from valibot.
You are right. Thank you! Can you share your schema that causes problems with React Hook Forms?
from valibot.
So I went ahead and read:
I think that this is currently only possible through detours. However, I am aware of the problem and I will try to find a solution in the long run.
For example, I could try to provide the entire input in a second parameter at
custom
, so that the validation can be done directly atstartsAt
. However, at this point, the validation is not yet complete, so the input could be incorrect and I would have to type it asunknown
.The second option would be to add to
custom
the ability to specify which field is affected by an error, so that the error can be output in the correct place.Until then, you can write your own validation function that throws a
ValiError
with path information tostartsAt
. Below is an example.import { coerce, date, object, parse, ValiError } from 'valibot'; const forceDate = (input: any) => new Date(input); export const Schema = object( { startsAt: coerce(date(), forceDate), endsAt: coerce(date(), forceDate), }, [ (input) => { if (input.startsAt > input.endsAt) { throw new ValiError([ { reason: 'date', validation: 'custom', origin: 'value', message: 'Invalid date', input: input.startsAt, path: [ { schema: 'object', input: input, key: 'startsAt', value: input.startsAt, }, ], }, ]); } return input; }, ] ); parse(Schema, { startsAt: 0, endsAt: 1000 }); // { startsAt: Date; endsAt: Date } parse(Schema, { startsAt: 1000, endsAt: 0 }); // Throws error
And started tinkering with it. Turns out that replacing the return input
statment with return { output: input }
statement did the trick.
So, I got my schema working as I wanted. It seems that react-hook-form
or @hookform/resolvers/valibot
doesn't like the idea of having a custom
pipeline method on an object
schema, this would require further research.
To conclude, I've got a working example in this StackBlitz. The TL;DR would be that I just removed the custom
pipeline method and added my own custom pipeline method.
P:S. @fabian-hiller, I wanted to know if you knew of a way in which I could improve this schema by making it easier to read.
Thanks in advance!
from valibot.
Hey, @fabian-hiller I was thinking of defining a custom pipe method like this:
import { type Pipe, ValiError } from "valibot";
type WhenArguments<TValues> = {
dependsOn: keyof TValues;
field: keyof TValues;
constraint: (input: TValues) => boolean;
};
type PipeMethod = <TValues>(
args: WhenArguments<TValues>,
message?: string
) => Pipe<TValues>[number];
export const when: PipeMethod =
({ dependsOn, field, constraint }, message) =>
(input) => {
if (
input[dependsOn] &&
typeof input[field] === "string" &&
constraint(input)
) {
return { output: input };
}
let genericMessage = "";
if (!message) {
const dependsOnPretty = (dependsOn as string).replace(
/([a-z])([A-Z])/g,
"$1 $2"
);
const dependsOnLabel =
dependsOnPretty.charAt(0).toUpperCase() +
dependsOnPretty.substring(1, dependsOnPretty.length);
genericMessage = `This field is required when the ${dependsOnLabel} field is provided`;
}
throw new ValiError([
{
reason: "string",
validation: "custom",
origin: "value",
message: message ?? genericMessage,
input: input[field],
path: [
{
schema: "object",
input: input as Record<string, unknown>,
key: field as string,
value: input[field],
},
],
},
]);
};
I wanted to get your feedback on this or to know if could improve it a little bit, thanks in advance!
from valibot.
Here's an example on StackBlitz with the prior idea ☝🏻
from valibot.
@demarchenac the internal implementation has changed with v0.13.0. Please read the release notes: https://github.com/fabian-hiller/valibot/releases/tag/v0.13.0
from valibot.
@fabian-hiller ok I understand now. So, the issue
syntax doesn't have a path
key to specify the error path, thus I ended up throwing a ValiError
. I'm new to this library so it took me a while to understand what you were referring to 😅
from valibot.
I'll try it out when re-writing my fieldRequiredWhen
implementation, thanks for getting this through!
from valibot.
Related Issues (20)
- [Proposal] Considering Biome for formating and linting HOT 1
- Branded schema doesn't provide the type guard thru the `is`. HOT 2
- Add CIDR Schema Type HOT 3
- Reporting of Errors (ValiError Format compared with ZodError Format) HOT 3
- Nullable, how can i do
- isoTimestamp only supports decimal fraction up to 3 digits HOT 8
- Cannot use `brand` with `url` or `email` HOT 1
- Document minimum typescript version HOT 7
- Nextjs build Failed HOT 6
- How can I define a schema so that it can be validated as a function? HOT 1
- getDefaults returns undefined for optional with a default of empty string or false HOT 2
- The validation of the object is not rigorous enough HOT 3
- Optional Objects with Literal Fields and Raw Default Result in "| undefined" Type HOT 1
- union(): Union wrong behavior when type validation pass HOT 2
- A GPT companion for the Zod to Valibot conversion HOT 1
- `union()` of object with overlapping field drops other fields HOT 4
- Supporte Metadata like description
- Support non-string array in `picklist` HOT 4
- customAsync not resolved inside issues? HOT 4
- Change omit() parameter type to `readonly TKeys[]` HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from valibot.