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.