Is there any way I can fetch the current collection name within the filter options?
you should have access to
relationTo
I believe
which would be the slug of the collection
@jarrod69420 According to the documentation, the "relationTo" parameter is used to filter based on the defined field relation, indicating that it is unrelated to the slug of the collection.
What are ya looking to do exactly?
something like that
filter: ({ data, id }) => {
if (!id) {
return { id: { exists: false } };
}
const currentCollection = ...
return { [
${currentCollection}.reference
]: { equals: id } };
},
You want to know the collection that the relationship field was defined in, like the parent config collection?
No, for example, if we have a URL like "
http://localhost:3000/cms/admin/collections/blogs/id", the currentCollection in this case should be "blogs"
This is related to this feature request:
https://github.com/payloadcms/payload/discussions/2829ohhh I see the issue here
is it that you want to
re-usea single
filterOptions
function across many different fields, but you need to know which collection the parent field is contained on?
because if i understand correctly, you let's say you have a blogs collection, and then there's some relationship field within the blogs collection. And you want to build a
filterOptions
function for that field, but that same function is also used on other collections
so you need to know if the
filterOptions
field is used on
blogs
or a different collection
if this is the case, the pattern that we typically suggest is to create a higher-order function, where you can pass in the collection name, along with any other data that you need, and then return a
filterOptions
function
so it would be like this:
type GetFilterOptionsArgs = {
collection: string
}
const getFilterOptions = (args: GetFilterOptionsArgs): FilterOptions => {
const { collection } = args;
// Return a typical filterOptions func here, but you now have access
// to the parent collection that it's used on
return ({ relationTo, siblingData }) => {
if (relationTo === "products") {
return {
stock: { greater_than: siblingData.quantity },
};
}
if (relationTo === "services") {
return {
isAvailable: { equals: true },
};
}
},
}
const myRelationshipField: Field = {
type: 'relationship',
name: 'myRelationshipField',
relationTo: ['products', 'services'],
// Call your higher-order function, passing in the collection slug
filterOptions: getFilterOptions({ collection: 'my-parent-collection' }),
}
if this is the case, the pattern that we typically suggest is to create a higher-order function, where you can pass in the collection name,
Yea we do this all over the place and it smells a bit funny to me - we have on order of 50 reusable "components" now and we're passing this info along in each of them. It's honestly a bit error prone and in some scenarios we need to pass these down multiple levels of nested fields/blocks and it's hard to track. IMO "data" knowing what data it actually represents it a pretty common pattern, Graphql does this natively with
__typename
It also feel a bit not DRY / redundant to have this setup all over the place:
const Posts = {
slug: 'posts',
fields: [
Hero({collection: 'posts'})
Additionally, in cases where a block contains a relationship field and is utilized across different collections, I believe we might encounter the same issue
@ssyberg i like the concept of exposing a collection in a variety of places, and i think we can build this at some point. there will be a lot to think through there though
there are a LOT of places that we will need to utilize this new feature
Word, I did a little proof of concept and a single line change made this available in all relationships but I already can tell it'll be much more in depth
filterOptions is one spot, but also - - validations, hooks, custom components, access control, defaultValue, probably more
and i'd like to identify a common pattern
like....
I added it in the data loader and that seemed promising, but I could see that it wasn't flowing through everywhere I wanted it
because sometimes it might be a collection, but sometimes it might be a global - and then sometimes you might be on a version
so it might need to be something like
context: { collectionSlug, globalSlug, isVersion, payloadAPI }
and likely more
the pattern i suggested should still work here
this was my first attempt at touching core code so I'm sure this is a silly approach:
result.docs.forEach((doc) => {
const docKey = JSON.stringify([
collection,
doc.id,
depth,
currentDepth,
locale,
fallbackLocale,
overrideAccess,
showHiddenFields,
]);
const docsIndex = keys.findIndex((key) => key === docKey);
doc._collection = collection;
if (docsIndex > -1) {
docs[docsIndex] = doc;
}
});
but yea I hear ya!
for the moment we're adding a beforeChange hook to all collections - we've already implemented an inheritance system so this is just a few lines in our "base collection"
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.