I'm trying to build out some custom form components, but I want them to be styled like the default payload components. I am able to import the components, but they don't come with an "onChange" handler, meaning I can't get the data out of them... has anyone successfully done this? I didn't see anything in the docs about it.
Okay @ninahorne version 0.13.6
deploys these new features into the Text
, Textarea
, Upload
, and Select
components.
Your original request was for Select
, so here's an example what a custom select component might look like (and here's the config for that field).
It works exactly as you might expect by exposing the onChange
and value
for you to manage freely. If you want this value to continue saving to the document (as the example illustrates), you can still sync it with context via the useField
hook.
Let us know if you have any troubles wiring this in!
Thank you so much!! I will let you know if I have an issues getting this up and running.
Hi @jacobsfletch I am in version 0.13.6 but I am unable to reference the SelectInput
or SelectInputType
in the example. The Select
field also appears to be the same as before, with no onChange
handler. Am I missing something? Here's my package.json:
{
"name": "payload-starter-typescript",
"description": "Blank template - no collections",
"version": "1.0.0",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"dev": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon",
"build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build",
"build:server": "tsc",
"build": "yarn build:payload && yarn build:server",
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.js NODE_ENV=production node dist/server.js"
},
"dependencies": {
"axios": "^0.23.0",
"coa": "^3.0.1",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"payload": "^0.13.6",
"styled-components": "^5.3.1",
"svgo": "^2.8.0",
"twilio": "^3.71.1",
"webpack": "^5.58.2"
},
"devDependencies": {
"@types/express": "^4.17.9",
"@types/styled-components": "^5.1.15",
"cross-env": "^7.0.3",
"nodemon": "^2.0.14",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}
Hey @ninahorne ā we just published a beta version where you can now import solely the inputs of the built-in Text
and Select
components. We'll be exposing more over time but for now these two should get you started!
If you yarn add payload@0.13.8-beta.0
- you'll then be able to import the inputs themselves like this:
import { TextInput, SelectInput } from 'payload/components/forms';
This should be what you need!
We'll document this information fully as soon as we publish a patch version inclusive of these changes. š
Have you seen the blog post on custom field components? https://payloadcms.com/blog/building-a-custom-field This goes a lot more in depth than what we put in the docs.
If you are importing fields directly from Payload, you might not have access to everything you need. Instead you can import the styles and use the setValue
from useFieldType
.
Does this help?
Yea, I've read the article, but I'm still struggling to replicate the Select field. Do you have any recommendations for this specific field type?
Can I ask what you custom functionality are you making with your select component? If it is something generally useful, it could be a candidate for a feature request.
You could recreate it by copying from the original and change what you need. This might not be the best way though.
Here is the component: https://github.com/payloadcms/payload/blob/master/src/admin/components/forms/field-types/Select/index.tsx
@jmikrut might have better ideas.
Basically, I have a component that has a list of careers and when a user selects a career it calls an API to get data for that career to populate a few more fields.
At first, I thought I could do this with a hook that waited for the value of the select to change, but I need this to happen instantaneously, not after the form is saved. So I guess my extension of the Select field is to add a custom onChange event to trigger an API call and then actually use the value from that call to update the form field.
Maybe my approach is incorrect. Is there a better way to trigger events when a field updates?
I've done some experimenting on this and I may have found an actual bug, or that I'm using the useFieldType in a way that it wasn't intended.
I thought it would be possible to have an additional useFieldType
with a path to another field within the same form to access setValue of additional fields.
const { setValue: setListNameValue } = useFieldType({
path: 'listName',
});
useEffect(() => {
setListNameValue(`${value} List`, true);
}, [value]);
In my code, setListNameValue is being called, but the value isn't being set properly. Debugging seems to indicate a race condition whereby the value change is dispatched as intended, but then another dispatch hits and immediately sets the listName value back.
I like what you're trying to achieve with the component, we should be able to make this work. I've pushed the concept I was playing with here: https://github.com/payloadcms/custom-field-guide/pull/new/adjacent-field-setvalue
I'll wait and see if others have any insight on this one.
Hey @ninahorne ā I see what you're looking to do. I have been thinking about this myself actually in another project.
We could extend built-in field components like Select
and Text
so that they accept an onChange
and value
handler.
If either onChange
or value
was passed to a field component, we would disable its own internal useFieldType
hook, and it would be up to you to send form values to and from the Payload form manually.
Then you could benefit from the exact same components that Payload UI uses.
Alternatively, right now, Payload SCSS is already exported and able to be re-used in custom components. There is a formInput
mixin that styles inputs easily but you'd still have to recreate your form's label and surrounding structure.
This approach would be easy enough and probably more performant for simple components like text inputs, but for Select
fields it could get more complicated due to having to replicate Payload's internal use of react-select
.
For Select
fields, another option there would be that Payload could export its internal ReactSelect
implementation which does take an onChange
and value
prop already. That component is shared between the relationship
and select
field types as well as a few other places in the UI.
Is there a route that you would prefer? We could work something up pretty quickly I'd expect!
I love the idea of adding an onChange
or value
handler! I could see many uses for that in my project, and I think it would be easier to keep my codebase more organized this way.
That's so awesome! Thank you so much
@ninahorne in the meantime could subscribe to your field's value using the useWatchForm
hook. An added benefit here is that form state is debounced. You would just need to be sure that your component doesn't re-render on every field change of the entire document, since this would happen very often.
@jacobsfletch that's really interesting! can you show me the docs for that?
@ninahorne there are no docs for this (yet) but here's a little snippet to help get you started:
import { useWatchForm } from 'payload/components/forms';
import { Props as TextFieldType } from 'payload/dist/admin/components/forms/field-types/Text/types';
export const CustomComponent: React.FC<TextFieldType> = (props) => {
const { path } = props;
const { fields } = useWatchForm();
const { value } = fields[path];
return (
<div>
{value}
</div>
)
}
I hope this is helpful!
@ninahorne we are actively working through the solution that @jmikrut described. You can follow the action in this pull request.
Wow this looks great! looks like this is merged in? Can i update and check it out?
We're almost there. One more merge (#376) should do it. I'll post the version number and demo code once it's been deployed.
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.