I am currently building a personal blog using Payload and, honestly, it's been an enjoyable process. The config structure is clean and easily understandable, and the documentation is fantastic.
However, I can't seem to find any documentation on how I should go about creating fields that can be generated through JavaScript. I have created a custom field to serve as the URL slug of a post, currently its used by manually typing out the title of the post in a URL safe format in the custom field. Though ideally it would use JavaScript to analyse the title and convert it to a URL safe string, auto-populating the slug and displaying it in the admin UI in a disabled text field.
So basically my question is how to set the value of a field in JavaScript based on the value of another field?
Hey @peniswafflexd
Glad to hear of your successes so far. Fortunately, what you describe is a common feature and pretty simple to setup. Since you already have a custom field, you're half way there.
To read the current value of another field in your document, use the getDataByPath
method from the useWatchForm
hook. Just send it the name of the field your are looking for. In your case, this is probably title
. Now you can format the href using this value, and render an anchor tag on the page.
To go the extra mile, you can also import Payload's CopyToClipboard
component and enhance the user experience.
import React from 'react';
import { useWatchForm } from 'payload/components/forms';
import CopyToClipboard from 'payload/dist/admin/components/elements/CopyToClipboard';
import { UIField } from 'payload/dist/fields/config/types';
export const AppUrlField: React.FC<UIField> = () => {
const { getDataByPath } = useWatchForm();
const title = getDataByPath('title');
const kebabTitle = title; // convert your title to a kebab-case string here, there are many ways to do this
const href = `https://yourapp.com/${kebabTitle}`; // swap in your own top-level domain here
return (
<div>
<div>
<span>
APP URL
</span>
<CopyToClipboard value={href} />
</div>
<div>
<a
href={href}
target="_blank"
rel="noopener noreferrer"
>
{href}
</a>
</div>
</div>
);
};
Hey @jacobsfletch ahh this is very helpful but not particularly what I was looking for, this will display exactly what I want in the admin UI, however, this won't actually change the value of the field in the database will it?
I need the 'kebab-title' to accessible via the API, and this seems to only change it on the front end and not store it? Am I correct or am I misinterpreting how this works?
Thanks for the quick reply!
Yep that makes perfect sense.
For that you'll want to render a custom text
field (as opposed to a ui
field illustrated above). To do this, you can leverage the setValue
method from the useField
hook to update the value of the field every time the title changes. We'll still use the useWatchForm
hook to keep up-to-date with the current document.
Then to go the extra mile again, we can also render Payload's text input with current value, so that the UI stays consistent with other fields in the admin panel.
import React, { useEffect } from 'react';
import { Props as TextFieldType } from 'payload/dist/admin/components/forms/field-types/Text/types';
import TextInputField from 'payload/dist/admin/components/forms/field-types/Text/Input';
import { useField, useWatchForm } from 'payload/components/forms';
import { FieldType as FieldType, Options } from 'payload/dist/admin/components/forms/useField/types';
export const AppURL: React.FC<TextFieldType & {
path: string
}> = (props) => {
const {
label,
name,
path,
} = props;
const field: FieldType<string> = useField({
label,
name,
path
} as Options);
const { fields } = useWatchForm();
const {
value,
setValue,
showError
} = field;
useEffect(() => {
const { title: { value: title } } = fields;
const kebabTitle = title; // convert your title to a kebab-case string here, there are many ways to do this
const newHref = `https://yourapp.com/${kebabTitle}`;
setValue(newHref);
}, [
fields,
setValue,
]);
return (
<TextInputField
path={name}
name={name}
onChange={setValue}
value={value}
showError={showError}
style={{
marginBottom: 0
}}
/>
);
};
Thats it! Thanks so much!
I didn't notice any react hooks in the documentation on the site, is this documentation available somewhere?
Also I don't know how to mark your comment as the answer
No problem! Documentation is in progress.
Star
Discord
online
Get dedicated engineering support directly from the Payload team..