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
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.