Skip to content

Instantly share code, notes, and snippets.

@Aberratio
Created September 13, 2022 05:12
Show Gist options
  • Save Aberratio/44fb8a5c4c4c73db91ff9db701bceb52 to your computer and use it in GitHub Desktop.
Save Aberratio/44fb8a5c4c4c73db91ff9db701bceb52 to your computer and use it in GitHub Desktop.
[Sanity.io v2] Sort and filter elements in an array of references

The code allows for arbitrary sorting and filtering of elements in an array of references in Sanity.io.

Supports Sanity.io version v2.

In the example given an array of references for two types, but you can limit it to one type or extend it as desired.

In the fetchElement() function, you can use a custom query so as to get the required elements.

import SortedReferenceSelect from './src/SortedReferenceSelect';
export default {
name: 'someDocumentName',
title: 'someDocumentTitle',
type: 'document',
fields: [
{
name: 'someName',
title: 'Some Title',
type: 'array',
of: [
{
type: 'reference',
to: [{ type: 'type1' }, { type: 'type2' }],
},
],
inputComponent: SortedReferenceSelect,
},
],
};
import React, { useEffect, useState } from 'react';
import { FormField } from '@sanity/base/components';
import PatchEvent, { set } from '@sanity/form-builder/PatchEvent';
import { useId } from '@reach/auto-id';
import sanityClient from 'part:@sanity/base/client';
import styled from 'styled-components';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import { nanoid } from 'nanoid';
const StyledSelect = styled(Select)`
width: 100%;
max-height: 50vh;
`;
const StyledFormControl = styled(FormControl)`
width: 100%;
`;
const SortedReferenceSelect = React.forwardRef((props, ref) => {
const [elements, setElements] = useState([]);
const [referencedElementRef, setReferencedElementRef] = React.useState('');
const [referencedElement, setReferencedElement] = React.useState('');
useEffect(() => {
const fetchElements = async () => {
await sanityClient
.fetch(
`*[(_type == 'type1' || _type == 'type2') && !(_id match "draft*")] | order(_createdAt desc){
_createdAt,
_type,
_id,
_rev,
}`,
)
.then((data) => {
const mappedData = data.map((el) => {
return { ...el, _ref: el._id, key: nanoid() };
});
setElements(mappedData);
});
};
fetchElements();
}, []);
useEffect(() => {
value && value[0] && value[0]._ref && setReferencedElementRef(value[0]._ref);
}, [value]);
useEffect(() => {
const fetchReferencedElement = async () => {
await sanityClient.fetch(`*[_id == "${referencedElementRef}"]`).then((data) => {
setReferencedElement(data[0]);
});
};
fetchReferencedElement();
}, [referencedElementRef]);
const { type, value, readOnly, markers, presence, compareValue, onChange } = props;
const handleChange = (element) => {
setReferencedElementRef(element._ref);
const selectedItem = elements.filter((el) => el._id && element._ref && el._id === element._ref)[0];
const toSet = [{ _key: selectedItem.key, _type: 'reference', _ref: selectedItem._ref }];
onChange(PatchEvent.from([set(toSet)]));
};
const inputId = useId();
return (
<FormField
description={type.description}
title={type.title}
__unstable_markers={markers}
__unstable_presence={presence}
compareValue={compareValue}
inputId={inputId}
readOnly={readOnly}
>
<StyledFormControl sx={{ m: 1, minWidth: 120 }} size="small">
<InputLabel id="select">ELement</InputLabel>
<StyledSelect labelId="selectELement" id="select" value={referencedElementRef} label="ELement">
{elements.map((element) => {
return (
<MenuItem
value={element._ref}
key={element.key}
onClick={() => handleChange(element)}
>
<div>Preview a single item in the drop-down list</div>
</MenuItem>
);
})}
</StyledSelect>
</StyledFormControl>
{value && referencedElement && <div>Preview of the selected item</div>}
</FormField>
);
});
export default SortedReferenceSelect;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment