Closed harshagr64 closed 4 months ago
You can create a custom component for the other dropdown and filter out results based on props.record.params
. props.record
holds the state of the form
@dziraf, can you give me a sample code on how can I achieve this?
is it possible to create custom component for specific dropdown instead of creating custom component for the complete screen in Admin js?
Please help me as I am new to the admin js & node js.
Yes, I'll help you tomorrow morning when I'm at work. Currently on a phone and it's inconvenient to write code
Sure @dziraf, Thanks!!
This is the default Reference component for edit
action:
Options are loaded on these lines:
const loadOptions = async (inputValue: string): Promise<SelectRecordEnhanced[]> => {
const api = new ApiClient()
const optionRecords = await api.searchRecords({
resourceId,
query: inputValue,
})
return optionRecords.map((optionRecord: RecordJSON) => ({
value: optionRecord.id,
label: optionRecord.title,
record: optionRecord,
}))
}
Let's say you have 2 dropdowns:
Subcategory should only display categories belonging to chosen Category. The above function would look this way then:
const loadOptions = async (inputValue: string): Promise<SelectRecordEnhanced[]> => {
const api = new ApiClient()
const optionRecords = await api.searchRecords({
resourceId,
query: inputValue,
params: {
'filters.categoryId': props.record?.params?.categoryId,
}
})
return optionRecords.map((optionRecord: RecordJSON) => ({
value: optionRecord.id,
label: optionRecord.title,
record: optionRecord,
}))
}
Full component:
import React, { FC, useState, useEffect, useMemo, memo } from 'react'
import { FormGroup, FormMessage, SelectAsync, Label } from '@adminjs/design-system'
import { ApiClient, EditPropertyProps, RecordJSON, flat, useTranslation } from 'adminjs'
type CombinedProps = EditPropertyProps
type SelectRecordEnhanced = {
record: RecordJSON;
label: string;
value: any;
}
const EditReference: FC<CombinedProps> = (props) => {
const { tp } = useTranslation()
const { onChange, property, record } = props
const { reference: resourceId } = property
if (!resourceId) {
throw new Error(`Cannot reference resource in property '${property.path}'`)
}
const handleChange = (selected: SelectRecordEnhanced): void => {
if (selected) {
onChange(property.path, selected.value, selected.record)
} else {
onChange(property.path, null)
}
}
const loadOptions = async (inputValue: string): Promise<SelectRecordEnhanced[]> => {
const api = new ApiClient()
const optionRecords = await api.searchRecords({
resourceId,
query: inputValue,
params: {
'filters.categoryId': props.record?.params?.categoryId,
}
})
return optionRecords.map((optionRecord: RecordJSON) => ({
value: optionRecord.id,
label: optionRecord.title,
record: optionRecord,
}))
}
const error = record?.errors[property.path]
const selectedId = useMemo(
() => flat.get(record?.params, property.path) as string | undefined,
[record],
)
const [loadedRecord, setLoadedRecord] = useState<RecordJSON | undefined>()
const [loadingRecord, setLoadingRecord] = useState(0)
useEffect(() => {
if (selectedId) {
setLoadingRecord((c) => c + 1)
const api = new ApiClient()
api.recordAction({
actionName: 'show',
resourceId,
recordId: selectedId,
}).then(({ data }: any) => {
setLoadedRecord(data.record)
}).finally(() => {
setLoadingRecord((c) => c - 1)
})
}
}, [selectedId, resourceId])
const selectedValue = loadedRecord
const selectedOption = (selectedId && selectedValue) ? {
value: selectedValue.id,
label: selectedValue.title,
} : {
value: '',
label: '',
}
return (
<FormGroup error={Boolean(error)}>
<Label property={property} >{tp('property.path'), property.resourceId}</Label>
<SelectAsync
cacheOptions
value={selectedOption}
defaultOptions
loadOptions={loadOptions}
onChange={handleChange}
isClearable
isDisabled={property.isDisabled}
isLoading={!!loadingRecord}
{...property.props}
/>
<FormMessage>{error?.message}</FormMessage>
</FormGroup>
)
}
export default EditReference
To replace the default component you should use ComponentLoader: https://docs.adminjs.co/ui-customization/writing-your-own-components
Getting this error with your code:
Object literal may only specify known properties, and 'params' does not exist in type '{ resourceId: string; query: string; searchProperty?: string; }'.
` const loadOptions = async (inputValue: string): Promise<SelectRecordEnhanced[]> => { const api = new ApiClient()
const optionRecords = await api.searchRecords({
resourceId,
query: inputValue,
params: {
'filters.categoryId': props.record?.params?.categoryId,
}
})
return optionRecords.map((optionRecord: RecordJSON) => ({
value: optionRecord.id,
label: optionRecord.title,
record: optionRecord,
}))
} const error = record?.errors[property.path] `
@dziraf please help me with the error.
Can anyone help me with this issue?
Thanks!!
change
const loadOptions = async (inputValue: string): Promise<SelectRecordEnhanced[]> => {
const api = new ApiClient()
const optionRecords = await api.searchRecords({
resourceId,
query: inputValue,
params: {
'filters.categoryId': props.record?.params?.categoryId,
}
})
return optionRecords.map((optionRecord: RecordJSON) => ({
value: optionRecord.id,
label: optionRecord.title,
record: optionRecord,
}))
}
to
const loadOptions = async (inputValue: string): Promise<SelectRecordEnhanced[]> => {
const api = new ApiClient()
const response = await api.resourceAction({
resourceId,
actionName: 'search',
query: inputValue,
params: {
'filters.categoryId': props.record?.params?.categoryId,
}
})
const { records: optionRecords } = response.data
return optionRecords.map((optionRecord: RecordJSON) => ({
value: optionRecord.id,
label: optionRecord.title,
record: optionRecord,
}))
}
Contact Details
No response
What happened?
List what you are trying to do?
Bug prevalence
Multiple Times
AdminJS dependencies version
7.2.0
What browsers do you see the problem on?
No response
Relevant log output
No response
Relevant code that's giving you issues
No response