#Can we conditionally change field type based on a sibling value?

14 messages · Page 1 of 1 (latest)

grizzled ledge
#

I have a scenario where user needs to select a field type, based on selection I want to show either a text field or a richText field for a sibling field in the same collection. As of now to make this work, I have 2 fields which I conditionally show/hide based on field type selection.

pliant tendon
#

You could use a custom component from type ui and handle it by yourself as you can access the values from other input fields with the useFields or useFormFields hook. https://payloadcms.com/docs/admin/hooks#usefield

Payload CMS

Payload is a headless CMS and application framework built with TypeScript, Node.js, React and MongoDB

topaz oak
#

@grizzled ledge I think this is what conditions are for and they should work nicely

#

Is the condition feature for fields not suitable?

#

I imagine you would do something like

#
        {
          name: "linkUrl",
          label: "Link URL",
          type: "text",
          required: false,
          admin: {
            condition: (data, siblingData, { user }) => {
              if (siblingData.linkType === "url") {
                return true;
              } else {
                return false;
              }
            },
          },
        },
#

where linkType is a select field type

#
        {
          name: "linkType",

          type: "select",
          hasMany: false,
          defaultValue: "url",
          admin: {
            description:
              "Select if the Link should go to another page, a PDF, or show a modal with text.",
          },
          options: [
            {
              label: "Link",
              value: "url",
            },
            {
              label: "PDF",
              value: "pdf",
            },
            {
              label: "Text",
              value: "text",
            },
          ],
        },
grizzled ledge
# topaz oak ```ts { name: "linkUrl", label: "Link URL", ...

This is precisely what I am doing right now, but I am ending up having 2 separate fields to handle both senarios

{
              name: "value",
              type: "text",
              label: "Value",
              required: true,
              admin: {
                condition: (_, siblingData) => siblingData.type !== 'richText',
              }
            },
            {
              name: "rvalue",
              type: "richText",
              label: "Value",
              admin: {
                condition: (_, siblingData) => siblingData.type === 'richText',
              }
            },```

But as @pliant tendon suggested, using a custom component will be a better solution
#

@pliant tendon Thanks for the suggestion, I will try it out

abstract depot
#

I am trying to use the custom component strategy to achieve conditional field types.

I need to decide the field type based on the selected reference field in the same array.
The problem is I don't know how to pass sibling data to the custom component. As this is an array, I cannot use the getSiblingData()as it requires hardcoded field name, which in case of an array, you wouldn't know.

How would one pass sibling data to custom component.

My collection:

...
  fields: [
            {
              name: 'attributesArray', // required
              type: 'array', // required
              minRows: 0,
              maxRows: 100,
              fields: [
                {
                  type: 'row', // required
                  fields: [
                    {
                      name: 'attribute',
                      type: 'relationship',
                      relationTo: ['attributes'],
                    },
                    {
                      name: 'featureValue',
                      type: 'ui',
                      admin: {
                        components: {
                          Field: () =>
                          FeatureValue({path: name}),
                        },
                      },
                    },
                  ]
                }
              ],
            },
          ],
...

FieldType (custom component)

const FeatureValue: React.FC = (props: { siblingData? }) => {
    // const { value, setValue } = useField<string>({ path })
    const [fields] = useAllFormFields();
    console.log("siblingData: ", siblingData)

    return (// return some component);
};

export default FeatureValue;

Additional question is how to access the referenced field fields? **
In this example**: I would need to access the referenced attribute's collection entity field named "dataType" which dictates the field type of the fieldValue field.

abstract depot
#

I believe the broader question here is, can one access the referenced entity in another collection "deeply" i.e. can I access all the fields of a referenced entity not just its id,

eternal marsh
abstract depot
#

I did. Via custom components @eternal marsh
Collection.ts

{
  type: 'row',
  fields: [
    {
      name: 'feature',
      type: 'relationship',
      relationTo: ['flFeatures'],
    },
    {
      name: "featureValue",
      type: "text",
      index: true,
      admin: {
        components: {
          Field: (props) => FeatureValue({ ...props}),
        },
      },
    },
  ]
}