Dynamic validation for optional object fields in Sanity.io

4 replies
Last updated: Oct 29, 2021
I've got an object with a bunch of fields with validation. The object is optional (using the
hidden()
function). Is there a way to only validate fields if the object they're part of is not hidden?
Oct 22, 2021, 3:21 PM
Ah right, but I don't know what the conditions will be, because this object can be used in a lot of different documents (it's a link type object, with label, internal en external field). Any way to get the actual hidden value used for the parent?
Oct 23, 2021, 10:48 AM
What does your object schema look like? I'll play around with it to see if I can make the validation rule dynamic based off of an unknown parent's visibility.
Oct 25, 2021, 4:46 PM
Cool, this is the
link
object:

export const link = {
  title: 'Link',
  name: 'link',
  type: 'object',
  fields: [
    {
      title: 'Type',
      name: 'type',
      type: 'string',
      initialValue: 'internal',
      options: {
        layout: 'radio',
        direction: 'horizontal',
        list: [
          { value: 'internal', title: `Internal` },
          { value: 'external', title: `External` }
        ]
      }
    },
    {
      title: 'Tekst',
      name: 'text',
      type: 'string',
      validation: Rule => Rule.required().error('This field is required')
    },
    {
      title: 'Url',
      name: 'internalLink',
      type: 'internalLink',
      hidden: ({ parent }) => parent?.type !== 'internal',
      validation: requiredIf(({ parent }) => parent?.type === 'internal')
    },
    {
      title: 'Url',
      name: 'externalLink',
      type: 'externalLink',
      hidden: ({ parent }) => parent?.type !== 'external',
      validation: requiredIf(({ parent }) => parent?.type === 'external')
    }
  ]
}

function requiredIf(fn) {
  return Rule => Rule.custom((value, context) => (!value && fn(context)) ? 'This field is required' : true).error()
}
It's used another object, chapter:


export const chapter = {
  title: 'Hoofdstuk',
  name: 'chapter',
  type: 'object',
  fields: [
    {
      title: 'Type',
      name: 'chapterType',
      type: 'string',
      options: {
        list: [
          { title: 'Afbeelding', value: 'image' },
          { title: 'Afbeelding met tekst', value: 'imageWithText' },
          { title: 'Video', value: 'video' },
          { title: 'Geanimeerde quote', value: 'animatedQuote' },
          { title: '360 Afbeelding', value: '360' },
          { title: 'Link', value: 'link' },
        ]
      },
      validation: Rule => Rule.required().error('Dit veld is verplicht')
    },
    {
      title: 'Link',
      name: 'link',
      type: 'link',
      hidden: ({ parent }) => !['link'].includes(parent?.chapterType),
      validation: Rule => Rule.custom((value, context) => (
        !value && context.parent?.chapterType === 'chapterWithLink'
          ? 'Dit veld is verplicht' 
          : true
      ).error()
    }
  ]
}
Oct 25, 2021, 7:48 PM
Not really possible, right?
Oct 29, 2021, 8:01 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?