I'm making a site where users can make applications. The application could be as a musician, volunteer, and various other types, which require asking different questions. There are fields that all will have in common (eg name, email), but others which I'd like to arrange in a more object-oriented, or at least DRY way.
The most simple way I can think of definitely achieving this is just having a collection for each application type, and extracting out the common fields to a module (more like inheritance). But I'd rather just have one application collection altogether that has a content field that provides the data for all the differing fields. Something like an enumerated field type where the content on an application could be a relation to another.
There might be a whole aspect of payload that I'm missing, but I can't find much on the docs that will support this. Can anyone point me in the right direction, or give me any tips or solutions?
Much appreciated!
Hey @sibergenome, how about conditional logic?
https://payloadcms.com/docs/fields/overview#conditional-logicYou could have an Applications collection, a 'type' select field, then fields that get conditionally rendered based on that type, like this:
export const Applications: CollectionConfig = {
slug: 'applications',
fields: [
{
name: 'type',
type: 'select',
options: [
{
label: 'Musician',
value: 'musician',
},
{
label: 'Volunteer',
value: 'volunteer',
},
{
label: 'Other',
value: 'other',
},
],
},
// all get this field
{
name: 'name',
type: 'text',
required: true,
},
// only musicians get this field
{
name: 'instrument',
type: 'text',
admin: {
condition: (_, {type}) => type === 'musician',
}
},
// only volunteers get this field
{
name: 'department',
type: 'text',
admin: {
condition: (_, {type}) => type === 'volunteer',
}
}
],
}
If you're going to have a lot of fields, you could put them in different groups and then apply the condition at a group level.
I use a series of functions - as the collections are just exported modules
My common fields are all behind a single "baseFields()" call, so I just call
fields: [baseFields(), {...}, {...}]
This allows me to define common fields shared across multiple collections, in one place, and manage them from there.
My collections generally have tabbed interfaces, with Content, Layout and Advanced tabs ... each having common fields within them, and then unique fields for that collection.
All of my fields are functions, I rarely define a field as an object-literal inside the collection itself.
fields: [
baseFields(), // slug, and other common things
labelField(), // row with text and select
titleField(), // row with text and select
contentField(), // richtext with specific definition
contentField('customName', CUSTOM_ARGS), // richtext with custom name, and some overrides to which leafs/elements are accessible
withCondition(labelField(), (data, siblingData) => { return siblingData.label.type == 'something'; }), // wrapper for admin: { condition: ... } }
]
Oh that's awesome, both are really good recommendations. I've noticed there's the recent form builder plugin, which could solve my problem, but having more complex field like hasMany relations seems like a bit of work.
Seems a mix of both of your solutions will do the trick since they're both flexible and hide complexity.
Thanks!
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.