Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Populate fields from external API based upon the value of an other field

default discord avatar
Deleted Userlast year
12

What I would like to achieve is – obviously – against the design of the Payloads API but i have found no other way to make the same UX.



I have a collection called

jobs

this collection has a field

listings

this field is a custom field which used an external api to populate data into a select field. This was the easy part.


Now, what I would like to do is listening for the changes of this

listings

field, and then give value from an API to other fields when it is changed.



The use case is: i have job listings collection which uses Workable API to get the current openings, so when you click on New button you should first select the listing, then the field would trigger a fetch to get the selected listing



Example:


export const Jobs: CollectionConfig = {
  slug: 'jobs',
  fields: [
    // What this does is, upon creation calls an API to fill itself with data.
   // Once the value changes, i would call an API again to give value for the `title` for example
    workableListings({
      name: 'listings',
      label: 'Select a workable listing',
    }),
    {
      type: 'text',
      label: 'Title',
      name: 'title',
      defaultValue: ''
    },
  ],
}


Unfortunately all the hooks run upon "save" button, so there is no way to use hooks for this. Nor i found any way to "call back" to fields when the field change



Okay I figured it out.



I don't have to go back to fields to manipulate the other fields. Instead within my custom field i can use the

useAllFormFields

hook to update other fields from my third-party source.


Note for future solution lurkers: this solution is pretty sketchy because once the external API changes the whole thing would just collapse.

  • default discord avatar
    augdust12 months ago

    do you have some example code for this? looking to implement a solution for this, having a collection in payload populated with data/items from an external api

  • default discord avatar
    notchr12 months ago
    @170674545965924352

    the defaultValue on fields can take a function that would allow you to async pull data



    You can use async defaultValue functions to fill fields with data from API requests.

    https://payloadcms.com/docs/fields/overview#default-values

    Also, similar thread here

    https://discord.com/channels/967097582721572934/1031993785971900556/threads/1237402299945582746
  • default discord avatar
    augdust12 months ago

    i'm looking to have a

    positions

    collection in payloadCMS which fetches data/positions from another system that our HR department uses to create and manage positions.



    We are just getting started using the new HR system, but I know they've got both a robust API and webhooks support. would just like to look at some example code, sounded like OP here had a similar case going on

  • default discord avatar
    notchr12 months ago

    For sure, I'm happy to make an example if you describe how the field should work



    I'm not sure if there is an official example, but I can also look

  • default discord avatar
    Deleted User12 months ago

    hey, happy to show ours. lemme put it together

  • default discord avatar
    augdust12 months ago

    i'm not 100 % on all fields, but i guess that from the external system a position would have basic info like a title, an office, an expiration date and maybe a department and a contact person etc. I imagine I'll have to create fields in Payload that copy their structure closely so they are easier to populate.



    then we probably want to extend the positions further with some additional data (tags, images etc), and this I imagine will be done in Payload - extra data for use on our website, a more presentational context

  • default discord avatar
    notchr12 months ago

    Yeah I've done something similar to that, totally doable

  • default discord avatar
    augdust12 months ago

    lovely! i've always figured it's doable, just a bit blue on where to start/how to code it in

  • default discord avatar
    notchr12 months ago

    You could try with a hook to start, beforeRead



    So that you can fire an event before the document loads



    https://payloadcms.com/docs/hooks/collections#beforeread

    Or you can just do it on a field-by-field basis



    Youll need to know what data you need to pull



    So that will likely be a field, maybe an ID



    then based on the value of the ID field, you can populate the other fields in the collection in one-go

  • default discord avatar
    Deleted User12 months ago
    // Created a custom field which looks like this:
    
    const workableListings = ({ name, label }: { name: string; label?: string }): TField => ({
      name,
      label: label || name,
      type: 'text',
      defaultValue: 'empty',
      required: true,
      validate: (value: string) => (value !== 'empty' ? true : 'Select a listing to continue'),
      admin: {
        components: {
          Field, // Field is where the magi happens
          Cell, // the cell is basically empty
        },
      },
    })
    
    // Field.tsx
    
    
    const Field: React.FC<Props> = ({ path, label, required, validate }) => {
      const {
        value = '',
        setValue,
        errorMessage,
        showError,
      } = useFieldType({
        path,
        validate,
      })
    
      const { submit } = useForm()
    
      async function saveAsDraft() {
        await submit({ overrides: { draft: true } })
      }
    
      useEffect(function initialize() {
        const fetchData = async () => {
          const response = await fetch('/api/careers')
          const data = await response.json()
          setListings(data.jobs)
        }
        fetchData()
      }, [])
    
      useEffect(
        function updateLatestFields() {
          latestFields.current = fields
        },
        [fields],
      )
    
      const fetchListingAndUpdateFields = async (id: string) => {
        const res = await fetch(`/api/careers/${id}`)
        const career = await res.json()
    
        Object.entries(PATH_TO_VALUE).forEach(([key, value]) => {
          dispatchFields({
            type: 'UPDATE',
            path: key,
            value: career[value],
          })
        })
    
        await saveAsDraft()
      }
    
    
      return (/* ... */)
    }
    export default Field


    removed some code to be able to fit in one message, if you have further questions feel free to ask



    the

    saveAsDraft

    was necessary because we found a strange bug in lexical where it does not updates the ui when you give some data to it using

    dispatchFields
  • default discord avatar
    augdust12 months ago

    thanks! will see if i can figure out something for my own solution with this

    :ShyPraise:
  • default discord avatar
    Deleted User12 months ago

    the key thing here is the custom field and the

    dispatchFields

    payload hook. those can save you in situations where you would need to mass update fields

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.