-
For example, If editor input I want another field slug to be auto-genrated with slug
|
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 6 replies
-
I've done a similar thing. I used the Given the following creator function:
I use it like so:
With help of course, from slugify. |
Beta Was this translation helpful? Give feedback.
-
Another implementation from the public demo: https://github.com/payloadcms/public-demo/blob/master/src/fields/slug.ts |
Beta Was this translation helpful? Give feedback.
-
what is the use case for this slug? I can't seem to wrap my head around because we can query with document id only. |
Beta Was this translation helpful? Give feedback.
-
A better solution for slug is to add a custom element:
|
Beta Was this translation helpful? Give feedback.
-
Here's an updated version of the @Stupidism solution: import React, { useEffect, useRef } from "react";
import { kebabCase } from "lodash";
import { TextInput, useFieldType } from "payload/components/forms";
import { TextField } from "payload/types";
export type SlugInputProps = TextField & {
trackingField: string;
};
export default function SlugInput(props: SlugInputProps) {
const {
trackingField,
required,
admin: { readOnly },
} = props;
const { value: slugValue = "", setValue: setSlugValue } =
useFieldType<string>({
path: "slug",
});
const { value: trackingFieldValue } = useFieldType<string>({
path: trackingField,
});
const prevTrackingFieldValueRef = useRef(trackingFieldValue);
const stopTrackingRef = useRef(false);
useEffect(() => {
if (!trackingField || stopTrackingRef.current) {
return;
}
if (trackingFieldValue === prevTrackingFieldValueRef.current) {
return;
}
const prevSlugValue = kebabCase(prevTrackingFieldValueRef.current);
prevTrackingFieldValueRef.current = trackingFieldValue;
if (prevSlugValue !== slugValue) {
return;
}
setSlugValue(kebabCase(trackingFieldValue));
}, [trackingFieldValue]);
return (
<div>
<TextInput
name="slug"
path="slug"
label="Slug"
description={
slugValue
? `Auto generated based on ${trackingField}`
: `Will be auto-generated from ${trackingField} when saved`
}
value={slugValue}
onChange={(e) => {
setSlugValue(e.target.value);
stopTrackingRef.current = true;
}}
readOnly={readOnly}
required={required}
/>
</div>
);
} import React from "react";
import { Field } from "payload/types";
import { merge } from "lodash";
import SlugInput from "../ui/SlugInput";
type Slug = (
options?: { trackingField?: string },
overrides?: Partial<Field>
) => Field;
export const slug: Slug = ({ trackingField = "title" } = {}, overrides) =>
merge<Field, Partial<Field> | undefined>(
{
name: "slug",
unique: true,
type: "text",
admin: {
position: "sidebar",
components: {
Field: (props) => (
<SlugInput trackingField={trackingField} {...props} />
),
},
},
},
overrides
); |
Beta Was this translation helpful? Give feedback.
-
Here's an updated version that works with Payload 3.0 // src/ui/SlugInput.tsx
'use client'
import { TextInput, useField } from '@payloadcms/ui'
import { kebabCase } from 'lodash'
import { useEffect, useRef } from 'react'
import { TextField } from 'payload'
export type SlugInputProps = TextField & {
trackingField: string
}
export function SlugInput(props: SlugInputProps) {
const { trackingField, required, admin: { readOnly } = {} } = props
const { value: slugValue = '', setValue: setSlugValue } = useField<string>({
path: 'slug',
})
const { value: trackingFieldValue } = useField<string>({
path: trackingField,
})
const prevTrackingFieldValueRef = useRef(trackingFieldValue)
const stopTrackingRef = useRef(false)
useEffect(() => {
if (!trackingField || stopTrackingRef.current) {
return
}
if (trackingFieldValue === prevTrackingFieldValueRef.current) {
return
}
const prevSlugValue = kebabCase(prevTrackingFieldValueRef.current)
prevTrackingFieldValueRef.current = trackingFieldValue
if (prevSlugValue !== slugValue) {
return
}
setSlugValue(kebabCase(trackingFieldValue))
}, [setSlugValue, slugValue, trackingField, trackingFieldValue])
return (
<div>
<TextInput
path="slug"
label="Slug"
hasMany={false}
description={
slugValue
? `Auto generated based on ${trackingField}`
: `Will be auto-generated from ${trackingField} when saved`
}
value={slugValue}
onChange={(e) => {
setSlugValue(e.target.value)
stopTrackingRef.current = true
}}
readOnly={readOnly}
required={required}
/>
</div>
)
} // src/fields/slug.ts
import lodash from 'lodash'
import { Field } from 'payload'
const { merge } = lodash
type Slug = (options?: { trackingField?: string }, overrides?: Partial<Field>) => Field
export const slug: Slug = ({ trackingField = 'title' } = {}, overrides) =>
merge<Field, Partial<Field> | undefined>(
{
name: 'slug',
unique: true,
type: 'text',
admin: {
position: 'sidebar',
components: {
Field: {
path: '../ui/SlugInput',
exportName: 'SlugInput',
clientProps: {
trackingField,
},
},
},
},
},
overrides,
) And then use it like: fields: [
{
name: 'title',
label: 'Title',
type: 'text',
maxLength: 128,
localized: true,
required: true,
},
slug({ trackingField: 'title' }),
], |
Beta Was this translation helpful? Give feedback.
A better solution for slug is to add a custom element: