Discussion about using conditional fields and array of references in a Sanity schema.
13 replies
Last updated: Sep 3, 2021
V
{ name:"category",
title:"Category",
type:"reference",
to: { type: "category" },
inputComponent: conditionalFields,
options:{
condition: (document, parent) => parent.articleType != "shortStories"
},
},
I want to select multiple items from the dropdown is it possible?
title:"Category",
type:"reference",
to: { type: "category" },
inputComponent: conditionalFields,
options:{
condition: (document, parent) => parent.articleType != "shortStories"
},
},
I want to select multiple items from the dropdown is it possible?
Sep 1, 2021, 10:47 AM
V
i tried this but didn't work{
title: 'Category',
name: 'categories,
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'category'},
]
}
]
},
title: 'Category',
name: 'categories,
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'category'},
]
}
]
},
Sep 1, 2021, 11:28 AM
V
This above works but when i do :inputComponent: conditionalFields,
options:{
condition: (document, parent) => parent.articleType != "shortStories"
},
it does not work it gives blank can anyone help me.
options:{
condition: (document, parent) => parent.articleType != "shortStories"
},
it does not work it gives blank can anyone help me.
Sep 1, 2021, 12:19 PM
V
Yes, I am using the conditionalField package to hide that field when articleType=="shortStories". When i use conditionalField i am getting this above error but when i remove the conditionalField it works perfect.
Sep 2, 2021, 4:23 AM
V
Yes, I am using the conditionalField package to hide that field when articleType=="shortStories". When i use conditionalField i am getting this above error but when i remove the conditionalField it works perfect.
Sep 2, 2021, 4:23 AM
V
I am using conditionalField file.import PropTypes from "prop-types";
import React from "react";
import * as PathUtils from '@sanity/util/paths'
import { FormBuilderInput, withDocument, withValuePath } from "part:@sanity/form-builder";
/**
* ConditionalField input component will wrap any regular input field configured
* with
*
* Inspired by the following code examples:
* -
https://sanity-io-land.slack.com/archives/C9Z7RC3V1/p1583362492389300?thread_ts=1583335061.341000&cid=C9Z7RC3V1 * -
https://github.com/sanity-io/sanity-recipes/blob/master/snippets/conditionalFieldsCustomInputComponent.js */
class ConditionalField extends React.Component {
// Declare shape of React properties
static propTypes = {
type: PropTypes.shape({
title: PropTypes.string,
options: PropTypes.shape({
condition: PropTypes.func.isRequired
}).isRequired
}).isRequired,
level: PropTypes.number,
focusPath: PropTypes.array,
onFocus: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func.isRequired
};
// Reference to input element
_inputElement = React.createRef();
// Called by the Sanity form-builder when this input should receive focus
focus() {
if (this._inputElement.current) {
this._inputElement.current.focus();
}
}
// Renders the form input if condition function returns true
render() {
const { document, getValuePath, value, level, focusPath, onFocus, onBlur, onChange } = this.props;
// Extract type without 'inputComponent' (self reference) to avoid infinite loop
const { inputComponent, ...type } = this.props.type;
// Find the active field's parent object in the document
const parentPath = getValuePath().slice(0, -1); // <- Remove current field from path
const parent = PathUtils.get(document, parentPath);
// Condition to evaluate if component should be shown, defaults to true
const defaultCondition = () => false;
const condition = (type.options && type.options.condition) || defaultCondition;
if (!condition(document, parent)) {
// Hide component
return null;
/**
* ----------------------------------------------------------------
* QUESTION
* How can we also delete the field value from the stored document?
* Running patch unset seems inefficient if it unsets the field
* every time the Studio UI is rendered, even though the stored
* document has not changed, but might be an acceptable solution.
* ----------------------------------------------------------------
*/
} else {
// Render component
return (
<div>
<FormBuilderInput
level={level}
ref={this._inputElement}
type={type}
value={value}
onChange={onChange}
path={[]}
// focusPath={focusPath}
onFocus={onFocus}
onBlur={onBlur}
/>
</div>
);
}
}
}
export default withValuePath(withDocument(ConditionalField));
import React from "react";
import * as PathUtils from '@sanity/util/paths'
import { FormBuilderInput, withDocument, withValuePath } from "part:@sanity/form-builder";
/**
* ConditionalField input component will wrap any regular input field configured
* with
options.conditionin the schema. *
*
option.conditionshould be a function that accepts two parameters,
document* and
parent, and returns
trueif the wrapped field should be shown. *
* Inspired by the following code examples:
* -
https://sanity-io-land.slack.com/archives/C9Z7RC3V1/p1583362492389300?thread_ts=1583335061.341000&cid=C9Z7RC3V1 * -
https://github.com/sanity-io/sanity-recipes/blob/master/snippets/conditionalFieldsCustomInputComponent.js */
class ConditionalField extends React.Component {
// Declare shape of React properties
static propTypes = {
type: PropTypes.shape({
title: PropTypes.string,
options: PropTypes.shape({
condition: PropTypes.func.isRequired
}).isRequired
}).isRequired,
level: PropTypes.number,
focusPath: PropTypes.array,
onFocus: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func.isRequired
};
// Reference to input element
_inputElement = React.createRef();
// Called by the Sanity form-builder when this input should receive focus
focus() {
if (this._inputElement.current) {
this._inputElement.current.focus();
}
}
// Renders the form input if condition function returns true
render() {
const { document, getValuePath, value, level, focusPath, onFocus, onBlur, onChange } = this.props;
// Extract type without 'inputComponent' (self reference) to avoid infinite loop
const { inputComponent, ...type } = this.props.type;
// Find the active field's parent object in the document
const parentPath = getValuePath().slice(0, -1); // <- Remove current field from path
const parent = PathUtils.get(document, parentPath);
// Condition to evaluate if component should be shown, defaults to true
const defaultCondition = () => false;
const condition = (type.options && type.options.condition) || defaultCondition;
if (!condition(document, parent)) {
// Hide component
return null;
/**
* ----------------------------------------------------------------
* QUESTION
* How can we also delete the field value from the stored document?
* Running patch unset seems inefficient if it unsets the field
* every time the Studio UI is rendered, even though the stored
* document has not changed, but might be an acceptable solution.
* ----------------------------------------------------------------
*/
} else {
// Render component
return (
<div>
<FormBuilderInput
level={level}
ref={this._inputElement}
type={type}
value={value}
onChange={onChange}
path={[]}
// focusPath={focusPath}
onFocus={onFocus}
onBlur={onBlur}
/>
</div>
);
}
}
}
export default withValuePath(withDocument(ConditionalField));
Sep 2, 2021, 1:01 PM
V
When i use this in category it does not refer to category i guess so and adds empty item.
Sep 2, 2021, 1:21 PM
One thing that may help: we recently released conditional fields within out of the box Studios. If you upgrade your studio, you can take advantage of this and simplify your schema.
Sep 2, 2021, 5:14 PM
V
How to upgrade the studio how to use it
Sep 2, 2021, 5:36 PM
You can upgrade the studio using
sanity upgradeand the link in the reply above will take you through the usage!
Sep 2, 2021, 5:38 PM
V
{ name: "articleType",
type: "string",
title: "Select Article Type",
initialValue:"Text",
options: {
list: [
{ title: "Text", value: "Text" },
{ title: "Audio", value: "audio" },
{ title: "Video", value: "video" },
{title:"Habit Cards", value:"cards"},
{title:"Short Stories", value:"shortStories"},
],
},
},
{
title: 'Categories',
name: 'categories',
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'category'},
]
}
],
hidden: ({ parent, value }) => parent.articleType==="shortStories",
},
I am doing this it does not display the category field in any condition can you please help.I want to hide when the articleType=="shortStories" how can i achieve that
type: "string",
title: "Select Article Type",
initialValue:"Text",
options: {
list: [
{ title: "Text", value: "Text" },
{ title: "Audio", value: "audio" },
{ title: "Video", value: "video" },
{title:"Habit Cards", value:"cards"},
{title:"Short Stories", value:"shortStories"},
],
},
},
{
title: 'Categories',
name: 'categories',
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'category'},
]
}
],
hidden: ({ parent, value }) => parent.articleType==="shortStories",
},
I am doing this it does not display the category field in any condition can you please help.I want to hide when the articleType=="shortStories" how can i achieve that
Sep 3, 2021, 9:57 AM
V
It worked for me on restarting server! How can i restricted that selecting reference doesn't get duplicated? like same category name cannot be selected multiple times.
Sep 3, 2021, 10:14 AM
V
Also want to add on how can i do conditional validation like when this field is not hidden i want it to be required.
Sep 3, 2021, 10:18 AM
V
Also want to add on how can i do conditional validation like when this field is not hidden i want it to be required.
Sep 3, 2021, 10:18 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.