Saskia Bobinska
Support Engineer @Sanity
Sometimes you want to validate items in an array, here is how
import { VscBrowser, VscMegaphone } from "react-icons/vsc";
import { isUniqueAcrossAllDocuments } from '../../src/isUniqueAcrossAllDocuments'
import SlugInput from 'sanity-plugin-better-slug'
import { basePath } from "../../src/basePath";
export default {
name: 'landingpage',
title: 'Landingpage',
type: 'document',
icon: VscBrowser,
groups: [
{
name: 'meta',
title: 'Meta',
}
],
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
initialValue: 'Landingpage',
},
{
title: 'Slug',
name: 'slug',
type: 'slug',
inputComponent: SlugInput,
readOnly: false,
options: {
basePath: basePath,
isUnique: isUniqueAcrossAllDocuments,
source: 'title',
maxLength: 200, // will be ignored if slugify is set
slugify: input => input
.toLowerCase()
.replace(/\s+/g, '-')
.slice(0, 200)
}
},
{
name: 'description',
title: 'Meta & SEO Description',
type: 'text',
description: 'Short and on point – max. 280',
maxLength: 280,
rows: 3,
group: 'meta',
},
{
name: 'image',
title: 'OG Image',
type: 'image',
group: 'meta',
validation: Rule => Rule.required(),
options: {
hotspot: true,
},
},
// Lets say you want to make sure, that only a heroSection OR a headerSection is added to the contentArray, but you need to add at least one...
{
name: 'contentArray',
title: 'Content',
type: 'array',
of: [
{ type: 'heroSection' }, //hero image header section
{ type: 'headerSection' }, // text based header section
{ type: 'textSection' },
{ type: 'cardSection' },
{ type: 'accordionSection' },
{ type: 'furtherLinkSection' },
{ type: 'tabSection' },
{ type: 'cta' }
],
},
],
preview: {
select: {
title: 'title',
subtitle: 'subline',
media: 'image'
}
}
}
{
name: 'contentArray',
title: 'Content',
type: 'array',
//The validation would look something like this:
validation: Rule => Rule.custom(content => {
// get the possible headers from the contentArray (if any are there)
const headers = (content || []).filter(
item =>
item._type === 'heroSection' || item._type === 'headerSection'
)
// create an array with the paths of these header items
const headerPaths = headers.map(
(header, index) => [{ _key: header._key }] || [index]
)
// See if headerPaths is longer then 1, if it is, there are too many headers and we then use the paths to mark the headers in the array and display the error message
return headerPaths.length === 1
? true
: {
message: 'There can only be one header section. Please delete one.',
paths: headerPaths
}
}),
of: [
{ type: 'heroSection' },
{ type: 'headerSection' },
{ type: 'textSection' },
{ type: 'cardSection' },
{ type: 'accordionSection' },
{ type: 'furtherLinkSection' },
{ type: 'tabSection' },
{ type: 'cta' }
],
},
Lets assume, you have a landingpage, where editors can add different page sections in an array called contentArray
.
But since you give the option to start the page with a heroSection or a text based headerSection you need to make sure, that editors don't add both or more to the content array.
You can do so by filtering the array items for the two _types
you want to control and creating a headerPaths
array, which you would also use to find the items and mark them as wrong in case the validation rule is broken.
What makes this so easy is, that you use headerPaths.length()
to determine, if there is more than one header section in the contentArray
of the page and use the passed down path
values (_key
and index
) to attach the error message to the items themselves.
Support Engineer @Sanity
How to validate nested fields from the document or object level
Go to Validation of children in objectsValidation of url input to allow certain URI schemes (mailto, tel and more included)
Go to Validation of url input to allow certain URI schemesAn Email field, that uses Regex-Validation.
Go to Email Field with Validation