Best way to do polymorphic or enumerated collection types?

default discord avatar
sibergenomelast year
3

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!

  • discord user avatar
    jesschow
    last year

    Hey @sibergenome, how about conditional logic?

    https://payloadcms.com/docs/fields/overview#conditional-logic

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

  • default discord avatar
    zoul0813last year

    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: ... } }
    ]
  • default discord avatar
    sibergenomelast year

    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 on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.