Filtering a reference list with dynamic filter in Sanity.io
13 replies
Last updated: Jan 28, 2021
M
Hey all! Real quick question for you. I'm trying to filter a reference list with a dynamic filter. This is where I'm currently at but it doesn't seem to do anything right now:
The document that this is being run within has a field
Any ideas, anyone?
filter: ({ document }) => { const ref = document.content?.product?._ref if (!ref) return return { filter: 'product._ref == $product', params: { product: ref, }, } },
content.productwhich references a
product, and the document type I am trying to filter here should also reference the same
product. You can't use
console.logwithin filter functions, so I have no way to be able to inspect what
documentcontains. I've tried a number of different ways of going about this, including checking for the presence of
document.contentand
document.content.productfirst, but nothing seems to make a difference here.
Any ideas, anyone?
Jan 28, 2021, 1:49 PM
M
The filter setup seems correct. Could you share your schema definition for the relevant document as well as the
productdocument type?
Jan 28, 2021, 2:19 PM
P
The filter setup seems correct. Could you share your schema definition for the relevant document as well as the
productdocument type?
Jan 28, 2021, 2:19 PM
D
Schema for document:
Jan 28, 2021, 2:27 PM
D
import React from 'react' import Tabs from 'sanity-plugin-tabs' const IntroStyle = (props) => ( <p style={{ textAlign: 'center', fontSize: '1.25rem', fontWeight: '600' }}> {props.children} </p> ) export const ProductPage = { title: 'Product Page', name: 'productPage', type: 'document', fields: [ { name: 'content', type: 'object', inputComponent: Tabs, fieldsets: [ { name: 'main', title: 'Main', options: { sortOrder: 10 } }, { name: 'meta', title: 'Meta', options: { sortOrder: 30 } }, { name: 'config', title: 'Options', options: { sortOrder: 50 } }, ], fields: [ { title: 'Product', name: 'product', type: 'reference', to: [{ type: 'product' }], fieldset: 'main', description: 'Select the product that this product page is about', options: { filter: `count(*[_type == 'productPage' && references(^._id)]) == 0`, }, }, { title: 'Page title', name: 'title', type: 'string', fieldset: 'main', description: '[OPTIONAL] Customise the title of this product page, if you do not want to use the product name', }, { title: 'Parent page', name: 'parentPage', type: 'reference', to: [{ type: 'page' }, { type: 'productPage' }], description: '[optional] set a parent page for this page to appear below in url structure', fieldset: 'main', }, { title: 'Page content', name: 'pageContent', type: 'array', of: [ { type: 'block', styles: [ { title: 'Normal', value: 'normal' }, { title: 'Intro', value: 'intro', blockEditor: { render: IntroStyle, }, }, { title: 'H2', value: 'h2' }, { title: 'H3', value: 'h3' }, { title: 'H4', value: 'h4' }, { title: 'Quote', value: 'quote' }, ], }, { type: 'productPage.hero' }, { type: 'productPage.intro' }, { type: 'columns' }, { type: 'image', fields: [ { title: 'Alt text', name: 'alt', type: 'text', options: { isHighlighted: true, }, }, ], options: { metadata: ['palette'], hotspot: true, }, }, { type: 'video' }, { type: 'gallery' }, { type: 'page.imageSlider' }, { type: 'page.richTextWithMedia' }, ], fieldset: 'main', }, { title: 'SEO / Meta Settings', name: 'meta', type: 'page.meta', fieldset: 'meta', }, { title: 'Enable sticky "Get a Quote" CTA?', name: 'hasStickyQuoteButton', type: 'boolean', description: '[optional] Enable the sticky header (desktop) / footer (mobile) Get a Quote CTA on this page', fieldset: 'config', }, { title: 'Technical files', name: 'technicalFiles', description: '[optional] Select which technical files associated with this product to show on the product page', type: 'array', of: [ { title: 'File', type: 'reference', to: [ { type: 'technicalFile', options: { filter: ({ document }) => { const ref = document.content?.product?._ref if (!ref) return {} return { filter: 'product._ref == $product', params: { product: ref, }, } }, }, }, ], }, ], fieldset: 'config', }, ], }, ], preview: { select: { pageTitle: 'content.title', productTitle: 'content.product.title', }, prepare(selection) { const { pageTitle, productTitle } = selection return { title: pageTitle || productTitle, } }, }, }
Jan 28, 2021, 2:27 PM
D
Technical file schema:
export const TechnicalFile = { title: 'File', name: 'technicalFile', type: 'document', fields: [ { title: 'Document Title', name: 'title', type: 'string', validation: (Rule) => Rule.required(), }, { title: 'File', name: 'file', type: 'file', validation: (Rule) => Rule.required(), }, { title: 'Document Code', name: 'code', type: 'string', }, { title: 'Product', name: 'product', type: 'reference', to: [{ type: 'product' }], }, { title: 'Document Type', name: 'doctype', type: 'string', options: { list: [ 'Installation instructions', 'Technical drawings', 'CAD file', 'Product data sheet', ], }, validation: (Rule) => Rule.required(), }, { title: 'Description', name: 'description', type: 'text', }, { title: 'Image', name: 'image', description: '[optional] Add an image to override the default product image to be shown in the file listing', type: 'image', fields: [ { title: 'Alt text', name: 'alt', type: 'text', options: { isHighlighted: true, }, }, ], options: { metadata: ['palette'], hotspot: true, }, }, ], }
Jan 28, 2021, 2:28 PM
D
Product is pretty much placeholder right now:
export const Product = { title: 'Product', name: 'product', type: 'document', fields: [ { title: 'Product name', name: 'title', type: 'string', validation: (Rule) => Rule.required(), }, { title: 'Featured image', name: 'image', type: 'image', fields: [ { title: 'Alt text', name: 'alt', type: 'text', options: { isHighlighted: true, }, }, ], options: { metadata: ['palette'], hotspot: true, }, validation: (Rule) => Rule.required(), }, ], }
Jan 28, 2021, 2:29 PM
D
To be clear, the document selector currently shows all documents of type
technicalFile, rather than filtering them.
Jan 28, 2021, 2:35 PM
P
Could you try moving your
optionsout of the
to[]array? So one level higher?
Jan 28, 2021, 2:36 PM
P
As follows:
{ title: 'File', type: 'reference', to: { type: 'technicalFile' }, options: { filter: ({ document }) => { const ref = document.content?.product?._ref if (!ref) return {} return { filter: 'product._ref == $product', params: { product: ref, }, } }, }, },
Jan 28, 2021, 2:39 PM
D
Yes, that's it. I'm an idiot and didn't see that I had it in the wrong place entirely! Thanks so much
user M
!Jan 28, 2021, 2:41 PM
P
An error would have helped I'm sure - not sure why it worked before π
Jan 28, 2021, 2:43 PM
D
It didn't. That was poor wording on my part. Seeing as Sanity is fully TypeScripted up now, this feels like something that could potentially be fairly easy to catch, as it is a property in a place that it shouldn't be
Jan 28, 2021, 2:50 PM
P
Yep, agreed. We could definitely improve error messages here and save some hair-pulling π
Jan 28, 2021, 3:01 PM
Sanityβ build remarkable experiences at scale
The Sanity Composable Content Cloud is the headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.