vinejs / vine

VineJS is a form data validation library for Node.js

Home Page:https://vinejs.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Combine Number AND Enum

Drulac opened this issue Β· comments

Package version

1.8.0

Describe the bug

Hello 😁 !

Sorry, Github won't let me use the Feature Request issue type, forced to submit it as Bug Report :-/

TLDR

[✨ New feature] : Requesting Number (to autoconvert HTML form string to number) and Enum (to ensure the number is from a predefined list) types combination, like this :

vine.number().enum([1, 3, 4, 8])

A bit of the request context

If I want to let my user choice between some objects (already in database, to use as relation) I could use an HTML select, and (dynamicly, using a template) pass every object id as value :

<select name="objectId" id="objectId">
    <option value="1">A Choice</option>
    <option value="3">B Choice</option>
    <option value="4">C Choice</option>
    <option value="8">D Choice</option>
</select>

Because in HTML forms, the values are always strings. My form will send "1", "2" or "3" (or whatever if the user alter the form).

If I want to save in DB a correct objectId for the relation, I need to convert the objectId from string to Number, and then check if there is actually an object with this id in my database.

Using  number().range instead of enum isn't possible because some object's id are unavailables.

It give me (using AdonisJS) a controller store method like that :

async store({ request }: HttpContext) {
    const data = request.all()

    //converting string to number
    if (data.objectId) {
      data.objectId = parseInt(data.objectId)
    }

    //getting all corrects objects id from DB
    const availableObjectIds = (await Object.all())
      .map((obj) => obj.serialize().id)
    //should be equal to [1, 3, 4, 8]
    data.availableObjectIds = availableObjectIds

    const payload = await Validator.validate(data)

    return Objet.create(payload)
}

With a Validator like that :

export const Validator = vine.compile(
  vine.object({
    objectId: vine.enum((field) => {
      //taking our ids picked from DB
      //should be equal to [1, 3, 4, 8]
      return field.parent.availableObjectIds
    }),
  })
)

With number and enum combined

I could drop theses lines from the controller :

//converting string to number
if (data.objectId) {
    data.objectId = parseInt(data.objectId)
}
async store({ request }: HttpContext) {
    const data = request.all()

    //getting all corrects objects id from DB
    const availableObjectIds = (await Object.all())
      .map((obj) => obj.serialize().id)
    //should be equal to [1, 3, 4, 8]
    data.availableObjectIds = availableObjectIds

    const payload = await Validator.validate(data)

    return Objet.create(payload)
}

And my validator will simply look like that :

export const Validator = vine.compile(
 vine.object({
   //converting string to number
   objectId: vine.number().enum((field) => {
     //taking our ids picked from DB
     //should be equal to [1, 3, 4, 8]
     return field.parent.availableObjectIds
   }),
 })
)

I'm asking this feature because I think it's better to keep data type validation inside models definitions

Thanks for all your work on the Adonis environnement !

Reproduction repo

No response

How about using the number schema with the in validation rule. Something like this

vine.number().in([1, 3, 4, 8])

Do note, the in validation rule does not exists, but it can be added

It could do the job very well 😁 !