How to create an Option Group in Antd Design? - reactjs

I'm trying to implement a categories input with this data returned from my DB
[
{
_id: '63e59f91bd2a21368188ff4b',
title: 'Uncategorized',
slug: 'uncategorized',
categoryType: 'blog',
createdAt: '2023-02-10T01:36:17.704Z',
updatedAt: '2023-02-10T01:36:17.704Z',
},
{
_id: '63e5984028745af5bad2c015',
parentCategory: {
_id: '63e5974a786719dd4bb2d37b',
title: 'Projects',
},
title: 'YTDownloader',
slug: 'ytdownloader',
categoryType: 'blog',
createdAt: '2023-02-10T01:05:04.919Z',
updatedAt: '2023-02-10T01:05:04.919Z',
},
{
_id: '63e597c3786719dd4bb2d387',
parentCategory: {
_id: '63e5974a786719dd4bb2d37b',
title: 'Projects',
},
title: 'Song Finder',
slug: 'song-finder',
categoryType: 'blog',
createdAt: '2023-02-10T01:02:59.742Z',
updatedAt: '2023-02-10T01:02:59.742Z',
},
]
What I'm trying is to create the example given in the documentation since my categories are pretty much 'parents' or 'childrens' and don't want to have them unorganized.
So far this is what I've been trying but to not success:
<Select
placeholder="Select category"
defaultValue={category}
onChange={(e) => {
setObjectData({
...objectData,
category: e,
})
}}
value={category}
options={[
categories.map((c, i) => [
{
label: c.parentCategory ? c.parentCategory.title : c.title,
},
]),
]}
/>
This returns literally nothing, not even an error. What I was expecting is the following:
<Select
defaultValue={category}
onChange={(e) => {
setObjectData({
...objectData,
category: e,
})
}}
value={category}
options={[
{
label: 'Projects',
options: [
{
label: 'YTDownloader',
value: '63e5984028745af5bad2c015',
},
{
label: 'Song Finder',
value: '63e597c3786719dd4bb2d387',
},
],
},
{
label: 'Uncategorized',
value: '63e59f91bd2a21368188ff4b'
],
},
]}
/>
Has anyone done something like this before? It will be great if you guys can help me solve this little issue that's been giving a headache for the last 2 hours, LOL

My guess would be you have only passed objects to options that only have a label and no value. This is speculation, but it's possible nothing is rendered in the dropdown if there is no corresponding value to each label.
The label, which is what the user sees for each option, isn't necessarily its underlying value.
Keep in mind the value is ultimately the thing that will be passed to onChange, so to only have a label with no value could explain why it just does nothing -- because a valid option must have a value.
Map each option such that its value represents that option uniquely:
categories.map((c, i) => [
{
label: c.parentCategory ? c.parentCategory.title : c.title,
value: c._Id
},
]),

Related

How to get select option label in addition to its value in react antd form?

I used antd-form-builder to create a form. The form contains select field (dropdown). I used form.getFieldValue("task") to get the value of selected option, I also need to get the label of selected option. how can I get it by clicking on a button?
const meta = (
fields: [
{
key: "task",
label: "Task",
widget: "select",
widgetProps: { showSearch: true },
options: [
{ label: "Pre-filter Replacement", value: 1 },
{ label: "Oil Change", value: 2 },
],
},
]
)
const handleClick = () => {
let taskValue = form.getFieldValue("task")
}
<Form form={form} onValuesChange={forceUpdate} onFinish={onFinish}>
<FormBuilder meta={meta} form={form} />
<Button onClick={handleClick}>Done</Button>
</Form>
You can use labelInValue prop to get the value along with selected option label.
Pass labelInValue: true, in widgetProps
const meta = {
fields: [
{
key: "task",
label: "Task",
widget: "select",
widgetProps: {
showSearch: true,
labelInValue: true,
},
options: [
{ label: "Pre-filter Replacement", value: 1 },
{ label: "Oil Change", value: 2 },
],
},
],
};
Now task value will not be a number buy an object containing label, value, key, disabled.
You can follow the Select API Documentation

MUI Textfield does not update State

I have an app which used various inputs which is functioning. For example, I have an initial dataset which is built from an API request, see below:
const [userData, setuserData] = useState([])
const companyuser = useSelector(state=>state.companyuser.currentUser)
useEffect(()=> {
const getUserData = async ()=>{
try{
const companyResponse = await userRequest.get(`companyprofile/findCompany/${companyuser._id}`);
setuserData(companyResponse.data.others)
}catch(err){}
};
getUserData()
},[])
const userInputDataSchema = [
{
id: 1,
label: "companyTitle",
type: "companyTitle",
placeholder: userData.companyTitle,
},
{
id: 2,
label: "surname",
type: "surname",
placeholder: userData.surname
},
{
id: 3,
label: "Email",
type: "email",
placeholder: userData.email
},
{
id: 4,
label: "Position",
type: "position",
placeholder: userData.position
},
{
id: 5,
label: "User Image",
type: "image",
placeholder: userData.userImage
},
{
id: 6,
label: "Professional Bio",
type: "professionalBio",
placeholder: userData.employees
},
{
id: 7,
label: "locationCity",
type: "locationCity",
placeholder: userData.locationCity
},
{
id: 8,
label: "locationCountry",
type: "locationCountry",
placeholder: userData.locationCountry
},
{
id: 9,
label: "whyWork_1",
type: "whyWork_1",
placeholder: userData.whyWork_1
},
];
This data is then mapped across the app, and will update when used. For example:
<UpdateUserDetailsSingular>
{userInputDataSchema.map((input) => (
<FormInput className="formInput" key={input.companyTitle}>
{input.id == 1 ?
<UserInput type={input.type} name="companyTitle" placeholder={input.placeholder}
onChange={handleChange} />
: null}
</FormInput>
))}
</UpdateUserDetailsSingular>
This is functioning. When I use the MUI larger input textfield, it does not update my state. It will dispaly the placeholder text, but if you type it will not handle it.
What is the reason?
{userInputDataSchema.map((input) => (
<div>
{input.id == 9 ?
<TextField
name="whyWork_1"
label="Diversity & Inclusion at Australia Post"
multiline
rows={15}
defaultValue={input.placeholder}
key={input.placeholder}
fullWidth
fullHeight
type={input.type}
handleChange={handleChange}
/> : null}
</div>
))}
</InputBoxContainer>
Does
The reason for this is could be a Mui related misconfiguration in TextField.
defaultValue any The default value. Use when the component is not controlled.
value any The value of the input element, required for a controlled component.
switching from defaultValue to value should do the job.

Antd Cascader component value/defaultValue showing ID instead of label

So I am using the Antd Cascader component (for the first time, having used Antd Select for most other things for the past few months). However, it isn't quite working yet. I have the options basically like this (but with a lot more options, only 3 levels deep tho like this):
const options = [
{
label: 'Base 1',
value: 'base_1',
children: [
{
label: 'Middle a',
value: 'middle_a',
children: [
{
label: 'Foo',
value: 'd57b2b75-4afa-4a16-8991-fc736bce8cd5',
},
{
label: 'Bar',
value: 'd12b2b75-4afa-4a16-8991-fc736bce8cec',
}
]
},
{
label: 'Middle b',
value: 'middle_b',
children: [
{
label: 'Baz',
value: 'd32b2b75-4afa-4a16-8991-fc736bce8cdd',
},
{
label: 'Quux',
value: 'dabb2b75-4afa-4a16-8991-fc736bce8ced',
}
]
}
]
},
{
label: 'Base 2',
value: 'base_2',
children: [
{
label: 'Middle a',
value: 'middle_a',
children: [
{
label: 'Helo',
value: 'd32bce75-4afa-4a16-8991-fc736bce8cdd',
},
{
label: 'World',
value: 'dabbac75-4afa-4a16-8991-fc736bce8ced',
}
]
}
]
}
]
I configure the component like this:
<Cascader
options={options}
getPopupContainer={trigger => trigger.parentNode}
multiple={multiple}
displayRender={label => {
return label.join(' / ');
}}
value={defaultValue}
// eslint-disable-next-line #typescript-eslint/no-explicit-any
onChange={(val: any, options: any) => {
if (multiple) {
const ids = serializeCascaderOptionValues(options);
onChange?.(ids, options);
} else {
onChange?.(val[2] ? String(val[2]) : undefined, options);
}
}}
showSearch={{
filter: (input: string, path) => {
return path.some(
option =>
String(option?.label).toLowerCase().indexOf(input.toLowerCase()) >
-1
);
},
}}
/>
Where, here, value or defaultValue I am passing in an array like ['d32bce75-4afa-4a16-8991-fc736bce8cdd'], which maps to Base 2 / Middle a / Helo. When I select the value Base 2 / Middle a / Helo from the UI, it shows correctly in the input like that. But when I save it and refresh the page (persisting to the backend, and pass in value={value} like value={['d32bce75-4afa-4a16-8991-fc736bce8cdd']}, it shows the ID hash in the input instead of the nice string Base 2 / Middle a / Helo. When I log displayRender={label...}, the label is showing the [ID-hash], rather than an array of like ['Base 2', 'Middle a', 'Helo']. What am I doing wrong, how do I get it to show properly?

Two React-Select dropdowns resetting each other

I have two dropdown menus using React-Select:
<Select
className="type-select"
options={type_options}
onChange={filterType}
/>
<label id='filter-label'>Filter By Generation:</label>
<Select
className="gen-select"
options={generation_options}
onChange={filterGen}
/>
and the options for the two of these are as follows:
{ value: 'none', label: 'None'},
{ value: 'normal', label: 'Normal' },
{ value: 'fire', label: 'Fire' },
{ value: 'water', label: 'Water' },
{ value: 'grass', label: 'Grass' },
{ value: 'electric', label: 'Electric' },
{ value: 'ice', label: 'Ice' },
{ value: 'fighting', label: 'Fighting' },
{ value: 'poison', label: 'Poison' },
{ value: 'ground', label: 'Ground' },
{ value: 'flying', label: 'Flying' },
{ value: 'psychic', label: 'Psychic' },
{ value: 'bug', label: 'Bug' },
{ value: 'rock', label: 'Rock' },
{ value: 'ghost', label: 'Ghost' },
{ value: 'dark', label: 'Dark' },
{ value: 'dragon', label: 'Dragon' },
{ value: 'steel', label: 'Steel' },
{ value: 'fairy', label: 'Fairy' },
];
const generation_options = [
{ value: 'none', label: 'None'},
{ value: 'i', label: 'I'},
{ value: 'ii', label: 'II'},
{ value: 'iii', label: 'III'},
{ value: 'iv', label: 'IV'},
{ value: 'v', label: 'V'},
{ value: 'vi', label: 'VI'},
{ value: 'vii', label: 'VII'},
{ value: 'viii', label: 'VIII'},
]
Both of these dropdowns are stored in state using React Hooks, and in the onChange methods for both, the value for the given Select is updated and the other is reset to "none". Ex: If my first select is set to "Fire" then when I change my second select to Gen IV, the first select sets back to "none". Functionally, I already have this working and am able to use the React-Selects as I want, but the issue I'm having is that when updating one select, the other select won't change to show that it's been changed. I've tried adding value={type} where type is the state the first select corresponds to, but that just causes the React-Select component to never show the selected value. Does anyone know how to get these React-Selects to operate in the way I'm describing? I can elaborate on parts of this more if more explanation is needed.
Thanks!
Edit: Here are the filterType and filterGen methods:
function filterType(selectedOption) {
setType(selectedOption.value)
setGen("none")
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`https://pokeapi.co/api/v2/type/${selectedOption.value}`)
}
}
function filterGen(selectedOption) {
setGen(selectedOption.value)
setType("none")
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`generation-${selectedOption.value}`)
}
}
Figured it out. The issue was I was setting the state to just the value of the selected item, instead of the whole object (ie: {value: 'fire', label: 'Fire}. Fixed pieces of code below, with the changes in bold:
function filterType(selectedOption) {
**setType(selectedOption)**
**setGen({ value: 'none', label: 'None'})**
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`https://pokeapi.co/api/v2/type/${selectedOption.value}`)
}
}
function filterGen(selectedOption) {
**setGen(selectedOption)**
**setType({ value: 'none', label: 'None'})**
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`generation-${selectedOption.value}`)
}
}
<div className="select-container">
<label id='filter-label'>Filter By Type:</label>
<Select
className="type-select"
options={type_options}
onChange={filterType}
**value={type}**
/>
<label id='filter-label'>Filter By Generation:</label>
<Select
className="gen-select"
options={generation_options}
onChange={filterGen}
**value={gen}**
/>
</div>

ReactiveSearch: Is it possible to combine label values on SingleDataList component?

I am trying to combine label values in the SingleDataList on reactive search. Using the example they provide below:
https://codesandbox.io/s/github/appbaseio/reactivesearch/tree/dev/packages/web/examples/SingleDataList?from-embed
This is the example they provide
<SingleDataList
title="SingleDataList"
componentId="CitySensor"
dataField="group.group_topics.topic_name_raw.raw"
data={[
{ label: 'Open Source', value: 'Open Source' },
{ label: 'Social', value: 'Social' },
{ label: 'Adventure', value: 'Adventure' },
{ label: 'Music', value: 'Music' },
]}
/>
My question is if its possible to combine the values of Social and Adventure into another label called "Social+Adventure"?
I have tried to use some logical operators below to test it out, as shown below but doesn't work.
<SingleDataList
title="SingleDataList"
componentId="CitySensor"
dataField="group.group_topics.topic_name_raw.raw"
data={[
{ label: 'Open Source', value: 'Open Source' },
{ label: 'Social + Adventure', value: 'Adventure' && 'Socal' },
{ label: 'Music', value: 'Music' },
]}
/>
Would there be any way that this is possible?
Thank you

Resources