How to create a custom input component in Sanity for updating fields based on dropdown selection
5 replies
Last updated: Oct 20, 2022
C
hello, I had a quick search but couldn't find what I was looking for,I have two objects (displayOptions & management)
In the management object I have a dropdown list with statuses and if a status equals a value then it would either check or uncheck a boolean field in my displayOptions field, for example if the status equals 'extended' then the extended checkbox would be true,
I've included a simplified version of my objects, is there a way to do this?
displayOptions.js:
management.js:
In the management object I have a dropdown list with statuses and if a status equals a value then it would either check or uncheck a boolean field in my displayOptions field, for example if the status equals 'extended' then the extended checkbox would be true,
I've included a simplified version of my objects, is there a way to do this?
displayOptions.js:
export default { name: 'displayOptions', title: 'Display Options', type: 'object', fields: [ { name: 'shortlist', title: 'Shortlist', type: 'boolean', initialValue: false, options: { layout: 'checkbox' }, }, { name: 'extended', title: 'Extended', type: 'boolean', description: 'TODO:', initialValue: false, options: { layout: 'checkbox' }, }, { name: 'omitted', title: 'Omitted', type: 'boolean', initialValue: false, options: { layout: 'checkbox' }, }, ], }
export default { name: 'management', title: 'Management', type: 'object', fields: [ { name: 'accessId', title: 'Access ID', type: 'string' }, { name: 'hotelStatusType', title: 'Hotel Status Type', type: 'tag', options: { predefinedTags: [ {label: 'Extended, value: 'extended'}, {label: 'Another Status', value: 'anotherStatus'},], } }, ], }
Oct 13, 2022, 9:44 AM
Hey
user Q
! Assuming these are sibling fields in the same document and not objects within an array (but feel free to correct me if I have that wrong!), you'll need to create a custom input component that you wrap in a withDocument HOC . I believe you could make either the hotelStatusTypeor
extendedFieldsa custom component that checks the value of the sibling field on the document then patches itself.
Oct 13, 2022, 5:48 PM
C
Hi
user M
, they are objects within the same document, I'm fairly new to sanity and custom input components but those links look promising, so I'll look into them, thank you! 🙂Oct 14, 2022, 7:17 PM
You're welcome! Just as a warning, custom input components seem super complex when you first approach them (and they kind of are 🙂 ) but once you start working with them you find that a great deal of it can be copy/pasted from the boilerplate props in the docs.
Oct 14, 2022, 8:44 PM
C
user M
Thank you for pointing me in the right direction! I got something working so I'm posting a simplified version here in case it helps anyone else - using document props I get my hotelStatusDropdown and with useEffect, set my checkbox if the title matches 🙂import React, { useEffect } from 'react'; import { withDocument } from 'part:@sanity/form-builder'; import { Checkbox } from '@sanity/ui'; import PatchEvent, { set, unset } from '@sanity/form-builder/PatchEvent'; import { useState } from 'react'; import styles from '../../brandStyling/styles/styles.css'; const StatusNotification = React.forwardRef((props, ref) => { const { value, // Current field value onChange, // Method to handle patch events type, } = props; // The status dropdown that determines display options const hotelStatusType = props.document.management.hotelStatusType; // Set the conditions where each display option checkbox will be true or not let hotelInGuide, hotelShortlist; if ( hotelStatusType === 'old' || hotelStatusType === 'New' ) { hotelInGuide = true; } let hotelOmitted = hotelStatusType === 'Omitted' ? true : false; // Hooks const [inputReadOnly, setInputReadOnly] = useState(false); // Functions const truePatchEvent = () => { onChange(PatchEvent.from('true' ? set(true) : set(false))); setInputReadOnly(true); }; const falsePatchEvent = () => { onChange(PatchEvent.from('false' ? set(false) : set(true))); setInputReadOnly(true); }; /** On page load & anytime the hotel status dropdown is changed we need to * update display option checkboxes * set to readOnly if applicable */ useEffect(() => { console.log('title:', type.title, 'statusType:', hotelStatusType); // Check to see what checkbox is current // In Guide Checkbox if (type.title === 'In Guide') { if (hotelInGuide) { console.log('in guide'); truePatchEvent(); } else if (hotelOmitted) { console.log('in guide gets unchecked - omitted!'); // uncheck in guide as the hotel is omitted falsePatchEvent(); } else { console.log('not in guide'); setInputReadOnly(false); } } // Omitted Checkbox - should always be readonly? if (type.title === 'Omitted') { if (hotelOmitted) { console.log('omitted'); truePatchEvent(); } else { console.log('not omitted'); falsePatchEvent(); } } }, [hotelStatusType]); // Creates a change handler for patching data - this visualises whether the checkbox is 'checked' or not const handleChange = React.useCallback( // useCallback will help with performance (event) => { console.log('event', event.target.checked, event.target); const inputValue = event.target.checked; // get current value onChange(PatchEvent.from(inputValue ? set(true) : set(false))); }, [onChange] ); return ( <div> <label className={inputReadOnly ? styles.labelReadOnly : styles.label}> <Checkbox checked={value} onChange={handleChange} readOnly={inputReadOnly} /> <span className={styles.checkboxText}>{type.title}</span> </label> </div> ); }); export default withDocument(StatusNotification);
Oct 20, 2022, 9:26 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.