πŸ‘€ Our most exciting product launch yet πŸš€ Join us May 8th for Sanity Connect

Validation of Array Items

By Saskia Bobinska

Sometimes you want to validate items in an array, here is how

landingpage.js

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'
        }
    }
}

contentArray validation

{
            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.

Contributor

Other schemas by author