set State doesn't update the value - reactjs

I have a problem with set State in dropdown semantic-ui-react.
I am using typescript in my code.
The selected category value doesn't change and always returns an empty string "". How can I fix this?
import debounce from "lodash.debounce";
import { observer } from "mobx-react-lite";
import React, { SyntheticEvent, useContext, useState } from "react";
import {
Dropdown,
DropdownItemProps,
DropdownProps,
Form,
InputOnChangeData,
Popup,
} from "semantic-ui-react";
import { RootStoreContext } from "../../../app/stores/rootStore";
const regex = new RegExp("^[a-zA-Z0-9 ]+$");
interface IProps {
loading: boolean;
}
const PurchaseDetailsFilter: React.FC<IProps> = ({ loading }) => {
const rootStore = useContext(RootStoreContext);
const {
setFilter,
itemCount,
loadPurchaseDetails,
categoryId,
setCategoryId,
} = rootStore.purchaseDetailStore;
const { purchaseCategories } = rootStore.purchaseCategoryStore;
const purchaseCategoriesList: any = purchaseCategories.map((data) => {
return { key: data.id, text: data.name, value: data.id };
});
const categoryOptions: DropdownItemProps[] = [
{ key: "all", value: "all", text: "All" },
].concat(purchaseCategoriesList);
const [selectedCategory, setSelectedCategory] = useState("");
const [filterValid, setFilterValid] = useState(true);
const f = debounce((value: string) => {
if (value !== "" && !regex.test(value)) {
setFilterValid(false);
setFilter(value);
} else {
setFilterValid(true);
console.log(loading);
setFilter(value);
loadPurchaseDetails();
}
}, 500);
const cat = debounce((value: string) => {
console.log(value);
setSelectedCategory(value as string);
console.log(selectedCategory);
setCategoryId((value ==="all" ? "" : value) as string);
loadPurchaseDetails();
}, 500);
const handleOnChange = (
event: React.ChangeEvent<HTMLInputElement>,
{ value }: InputOnChangeData
) => {
f(value);
};
let popupMessage = "";
if (!filterValid) {
popupMessage = "Invalid character.";
} else if (itemCount === 0) {
popupMessage = "No results found.";
}
const handleSelectedCategory = (
event: SyntheticEvent<HTMLElement>,
{value}: DropdownProps
) => {
console.log(value);
setSelectedCategory(String(value));
console.log(selectedCategory);
setCategoryId((value ==="all" ? "" : value) as string);
loadPurchaseDetails();
};
return (
<Form>
<Form.Group>
<Form.Field>
<Popup
trigger={
<Form.Input
placeholder={"Enter a filter."}
name={"filter"}
error={!filterValid}
label={"Filter"}
onChange={handleOnChange}
icon={"search"}
loading={loading}
/>
}
content={popupMessage}
on={"click"}
open={!filterValid || itemCount === 0}
position={"right center"}
/>
</Form.Field>
<Form.Field style={{ marginLeft: "10em" }}>
<label>Category</label>
<Dropdown
//defaultValue="All"
//value={categoryId}
value={selectedCategory}
onChange={handleSelectedCategory}
//defaultValue={categoryOptions[0].value}
placeholder="Choose an category"
options={categoryOptions}
selection
/>
</Form.Field>
<Form.Field>
<label>Project</label>
<Dropdown placeholder="Choose an option" />
</Form.Field>
<Form.Field>
<label>Supplier</label>
<Dropdown placeholder="Choose an option" />
</Form.Field>
</Form.Group>
</Form>
);
};
export default observer(PurchaseDetailsFilter);

maybe what you are looking for is this one:
const handleSelectedCategory = (
event: SyntheticEvent<HTMLElement>,
{value}: DropdownProps
) => {
console.log(value);
setSelectedCategory(String(value));
console.log(selectedCategory);
setCategoryId(String(value ==="all" ? "" : value));
loadPurchaseDetails();
};
notice that I changed value as string to be String(value).
I once fiddle around with TypeScript, but I forget how as string casting works. You might find better explanation here: https://stackoverflow.com/a/32607656/7467018

Have a look at the below code comment
const handleSelectedCategory = (
event: SyntheticEvent<HTMLElement>,
{ value }: DropdownProps
) => {
console.log(value); // If this value is string i.e "Hello World", then just call setSelectedCategory(value);
setSelectedCategory(value as string); // Not required. Just call setSelectedCategory(value) if value is string.
console.log(selectedCategory);
setCategoryId((value === "all" ? "" : value) as string); // Curious, where is setCategoryId froming from?
loadPurchaseDetails();
};

Related

react-select: Impossible to get value onBlur event

I have a problem with the react-select lib (see here: https://www.npmjs.com/package/react-select). For the validation of my form, I display an error message on the onBlur event. The problem is that no value appears in my logs.
However, onChange works fine.
Handler
const handleBlur = (e: FocusEvent<HTMLInputElement, Element>) => {
//Here, When I select a value and deselect the input, no value exists in this log.
console.log("value Select: ", e.target.value )
}
The return of my component function
<Select
placeholder={`Select ${name}`}
name={name}
id={id}
onBlur={(e) => {
handleBlur(e)
}}
onChange={(e) => {
setValueOnChange(e, name)
}}
options={options}
styles={customStyle}
/>
Anyone have a suggestion?
Thanks !
import "./styles.css";
import Select from "react-select";
import { useState } from "react";
export default function App() {
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
];
const [value, setValue] = useState();
const [focusValue, setFocusValue] = useState();
const handleChange = (changeValue) => {
setValue(changeValue);
};
const handleFocus = (event) => {
const focusValue = event.target.value;
console.log("Should be focus value", focusValue);
setFocusValue(focusValue);
};
const handleBlur = (event) => {
const blurValue = event.target.value;
console.log("Should be blur value", blurValue);
if (focusValue !== blurValue) {
console.log("Do something");
}
};
return (
<div className="App">
<h1>React Select onFocus & onBlur </h1>
<Select
options={options}
value={value}
onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur}
/>
</div>
);
}

Is there a way to handle state in a form that is dynamically built based off of parameters sent from the back end

I have a page in react 18 talking to a server which is passing information about how to build specific elements in a dynamic form. I am trying to figure out how to manage state in a case where there are multiple selects/multiselects in the page. Using one hook will not work separately for each dropdown field.
Code is updated with the latest updates. Only having issues with setting default values at this point. Hooks will not initially set values when given.
import { Calendar } from 'primereact/calendar';
import { Dropdown } from 'primereact/dropdown';
import { InputSwitch } from 'primereact/inputswitch';
import { InputText } from 'primereact/inputtext';
import { MultiSelect } from 'primereact/multiselect';
import React, { useEffect, useState, VFC } from 'react';
import { useLocation } from 'react-router-dom';
import { useEffectOnce } from 'usehooks-ts';
import { useAppDispatch, useAppSelector } from 'redux/store';
import Form from '../components/ReportViewForm/Form';
import { getReportParamsAsync, selectReportParams } from '../redux/slice';
export const ReportView: VFC = () => {
const location = useLocation();
const locState = location.state as any;
const dispatch = useAppDispatch();
const reportParams = useAppSelector(selectReportParams);
const fields: JSX.Element[] = [];
const depList: any[] = [];
//const defaultValList: any[] = [];
//dynamically setting state on all dropdown and multiselect fields
const handleDdlVal = (name: string, value: string) => {
depList.forEach((dep) => {
if (name === dep.dependencies[0]) {
dispatch(getReportParamsAsync(currentMenuItem + name + value));
}
});
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
//dynamically setting state on all calendar fields
const handleCalVal = (name: string, value: Date) => {
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
//dynamically setting state on all boolean fields
const handleBoolVal = (name: string, value: boolean) => {
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
/* function getInitVals(values: any) {
const defaultList: any[] = [];
values.forEach((param: any) => {
defaultList.push({ name: param.name, value: param.defaultValues[0] });
});
} */
const [state, setState] = useState<any>({});
const [currentMenuItem, setCurrentMenuItem] = useState(locState.menuItem.id.toString());
useEffectOnce(() => {}), [];
useEffect(() => {
if (reportParams?.length === 0) {
dispatch(getReportParamsAsync(currentMenuItem));
}
//reload hack in order to get page to load correct fields when navigating to another report view
if (currentMenuItem != locState.menuItem.id) {
window.location.reload();
setCurrentMenuItem(locState.menuItem.id.toString());
}
}, [dispatch, reportParams, currentMenuItem, locState, state]);
//dependency list to check for dependent dropdowns, passed to reportddl
reportParams.forEach((parameter: any) => {
if (parameter.dependencies !== null && parameter.dependencies[0] !== 'apu_id') {
depList.push(parameter);
}
});
//filter dispatched data to build correct fields with data attached.
reportParams.forEach((parameter: any, i: number) => {
if (parameter.validValuesQueryBased === true) {
if (parameter.validValues !== null && parameter.multiValue) {
const dataList: any[] = [];
parameter.validValues.map((record: { value: any; label: any }) =>
dataList.push({ id: record.value, desc: record.label }),
);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<MultiSelect
options={dataList}
name={parameter.name}
value={state[parameter.name]}
onChange={(e) => handleDdlVal(parameter.name, e.value)}
></MultiSelect>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.validValues !== null) {
const dataList: any[] = [];
parameter.validValues.map((record: { value: any; label: any }) =>
dataList.push({ id: record.value, desc: record.label }),
);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<Dropdown
options={dataList}
optionValue='id'
optionLabel='desc'
name={parameter.name}
onChange={(e) => handleDdlVal(parameter.name, e.value)}
value={state[parameter.name]}
//required={parameter.parameterStateName}
placeholder={'Select a Value'}
></Dropdown>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
}
} else if (parameter.parameterTypeName === 'Boolean') {
fields.push(
<span key={i} className='col-12 mx-3 field-checkbox'>
<InputSwitch
checked={state[parameter.name]}
id={parameter.id}
name={parameter.name}
onChange={(e) => handleBoolVal(parameter.name, e.value)}
></InputSwitch>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.parameterTypeName === 'DateTime') {
//const date = new Date(parameter.defaultValues[0]);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<Calendar
value={state[parameter.name]}
name={parameter.name}
onChange={(e) => {
const d: Date = e.value as Date;
handleCalVal(parameter.name, d);
}}
></Calendar>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.name === 'apu_id') {
return null;
} else {
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<InputText name={parameter.name}></InputText>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
}
});
const onSubmit = () => {
console.log(state);
};
return (
<Form onReset={null} onSubmit={onSubmit} initialValues={null} validation={null} key={null}>
{fields}
</Form>
);
};
enter code here

Unhandled Rejection (TypeError): Cannot read properties of undefined (reading 'reduce')

I am working on yup validation. Whenever it comes to FileList validation, if I left the input blank, I got the following error:
enter image description here
Here is my code:
import React, { useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router';
import { useDispatch, useSelector } from '#app/hooks';
import { Button, Dimmer, Dropdown, DropdownItemProps, DropdownProps, Form, Header, Loader, Modal } from 'semantic-ui-react';
import { NewBook, TestBook, UpdateParam } from '#app/reducers/master-data/book/book.model';
import * as yup from "yup";
import { useForm } from 'react-hook-form';
import { yupResolver } from '#hookform/resolvers/yup';
import { useHistory } from 'react-router-dom';
import { _getAllGenres } from '#app/reducers/master-data/genre/genre.slice';
import { _getAllPublisher } from '#app/reducers/master-data/publisher/publisher.slice';
import { _getAllAuthors } from '#app/reducers/master-data/author/author.slice';
import { _getAllDepartment } from '#app/reducers/master-data/department/department.slice';
import { _updateBook, _getAllBooks, _getBookDetail, _uploadBookFile } from '#app/reducers/master-data/book/book.slice';
import { Wrapper } from '#app/components/data-table/StyledComponent';
import { IBookParam } from '#app/reducers/master-data/book/book.service';
interface IProps {
}
interface ErrMessage {
type: string,
message: string
}
const schema = yup.object().shape({
title: yup.string().required('Title cannot blank'),
publishYear: yup.number(),
isPublic: yup.boolean(),
language: yup.string(),
authorIDs: yup.array(),
genreIDs: yup.array(),
description: yup.string(),
// departmentIDs: yup.array(),
publisherID: yup.number(),
file: yup
.mixed()
.required("A random message")
.nullable(false)
.test("Empty file", "You need to provide a file", (value: FileList) => {
let x = value.length !== 0
debugger
return value.length !== 0;
})
.test("type", "Only support PDF file", (value: FileList) => {
return value[0].type === "application/pdf"
})
});
const UpdateBookPage: React.FC<IProps> = (props) => {
const dispath = useDispatch()
const history = useHistory();
useEffect(() => {
dispath(_getAllGenres());
dispath(_getAllPublisher());
dispath(_getAllAuthors());
dispath(_getAllDepartment());
// dispath(_getAllBooks());
dispath(_getBookDetail(id));
}, [])
const search = useLocation().search;
const query = new URLSearchParams(search);
const id = query.get('id') || '';
const genres = useSelector(state => state.genre).genres;
const publishers = useSelector(state => state.publisher).publishers;
const authors = useSelector(state => state.author).authors;
const departments = useSelector(state => state.department).departments;
const book = useSelector(state => state.book.selectedBook);
const isLoading = useSelector(state => state.book.isLoading);
const statusCode = useSelector(state => state.book.statusCode);
// console.log(book)
const defaultDepartments = useMemo<number[]>(() => {
let temp: number[] = []
for (let x of book.departments) {
temp.push(x.id)
};
return temp;
}, [book.departments])
const defaultAuthors = useMemo<number[]>(() => {
let temp: number[] = []
for (let x of book.authors) {
temp.push(Number(x.id))
};
return temp;
}, [book.authors])
const defaultGenres = useMemo<number[]>(() => {
let temp: number[] = []
for (let x of book.genres) {
temp.push(Number(x.id))
};
return temp;
}, [book.genres])
const departmentOptions = useMemo<DropdownItemProps[]>(() => {
let temp: DropdownItemProps[] = []
for (let x of departments) {
temp.push({
key: x.id,
text: x.name,
value: x.id
})
};
return temp;
}, [departments])
const genreOptions = useMemo<DropdownItemProps[]>(() => {
let temp: DropdownItemProps[] = []
for (let x of genres) {
temp.push({
key: x.id,
text: x.name,
value: x.id
})
};
return temp;
}, [genres])
const authorOptions = useMemo<DropdownItemProps[]>(() => {
let temp: DropdownItemProps[] = []
for (let x of authors) {
temp.push({
key: x.id,
text: x.fullName,
value: x.id
})
};
return temp;
}, [authors])
const [openForm, setOpenForm] = useState<boolean>(false)
const [authorSelected, setAuthorSelected] = useState<Number[]>([...defaultAuthors]);
const [genreSelected, setGenreSelected] = useState<Number[]>([...defaultGenres]);
const [departmentSelected, setDepartmentSelected] = useState<Number[]>([...defaultDepartments]);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [fileErrorText, setFileErrorText] = useState<string>('');
// const [selectedFile, setSelectedFile] = useState<File|null>(null);
const [isOpen, setIsOpen] = useState<boolean>(false);
const [alertText, setAlertText] = useState<string>('');
const [isFailed, setIsFailed] = useState<boolean>(false);
const [errMessage, setErrMessage] = useState<ErrMessage>({
type: '',
message: ''
})
const { register, handleSubmit, formState: { errors }, setValue, trigger } = useForm<TestBook>({
resolver: yupResolver(schema),
// defaultValues: defaultBook
});
useEffect(() => {
if (book) {
setInitValue()
}
}, [book])
const setInitValue = () => {
setValue('title', book.title)
setValue('publishYear', book.publishYear)
setValue('authorIDs', [...defaultAuthors])
setValue('language', 'vi')
setValue('departmentIDs', [...defaultDepartments])
setValue('description', book.description)
setValue('genreIDs', [...defaultGenres])
setValue('isPublic', book.isPublic)
setValue('publisherID', Number(book.publisher.id))
}
// console.log(defaultAuthors, defaultDepartments, defaultGenres)
const handleSubmitBtn = async (data: NewBook) => {
debugger
console.log(data);
const valid = validateData();
debugger
if (valid) {
data.authorIDs = authorSelected.concat(defaultAuthors);
data.genreIDs = genreSelected.concat(defaultGenres)
data.departmentIDs = departmentSelected.concat(defaultDepartments)
const updateParam: UpdateParam = {
id: id,
newBook: data
}
console.log(data);
console.log(selectedFile);
try {
debugger
await dispath(_updateBook(updateParam)).then(() => {
if (statusCode == 200) {
if (selectedFile != null) {
let formData = new FormData();
formData.append("FILE", selectedFile);
formData.append("NAME", selectedFile.name);
const param: IBookParam = {
id: localStorage.getItem("BOOKID") || '',
file: formData
}
console.log(param.file);
console.log(param.id);
dispath(_uploadBookFile(param)).then(() => {
if (statusCode == 200) {
setIsOpen(true);
console.log(isOpen);
setAlertText("Update successfully")
} else {
setIsOpen(true)
setAlertText("An error has occured. Please try again later");
setIsFailed(true);
}
})
} else {
return;
}
}
console.log(data);
})
}
catch {
setIsOpen(true)
setAlertText("An error has occured. Please try again later");
setIsFailed(true);
}
}
}
const validateData = (): boolean => {
let x = authorSelected.concat(defaultAuthors)
let y = genreSelected.concat(defaultGenres)
let z = departmentSelected.concat(defaultDepartments)
debugger
if (authorSelected.concat(defaultAuthors).includes(0)) {
setErrMessage({
type: "AUTHOR",
message: "At least one author must be selected"
});
return false;
} else if (genreSelected.concat(defaultGenres).includes(0)) {
setErrMessage({
type: "GENRE",
message: "At least one genre must be selected",
});
return false;
} else if (departmentSelected.concat(defaultDepartments).includes(0)) {
setErrMessage({
type: "DEPARTMENT",
message: "At least one department must be selected",
});
return false;
}
return true;
}
const handleAddItem = (data: DropdownProps, type: string) => {
let val = JSON.stringify(data.value)
let numArr: Number[] = []
val = val.substring(1, val.length - 1)
let valArr = val.split(',');
// console.log(valArr);
for (let x of valArr) {
numArr.push(Number(x))
// console.log(numArr)
}
console.log(numArr)
// const y: Number[] = numArr
switch (type) {
case "AUTHOR":
setValue("authorIDs", numArr)
setAuthorSelected(numArr)
break;
case "GENRE":
setValue("genreIDs", numArr)
setGenreSelected(numArr);
break;
case "DEPARTMENT":
// if(numArr.length > 5){
// setErrMessage({
// type: "Department",
// message: "You can only select maximum of 5 departments"
// })
// break;
// }
setValue("departmentIDs", numArr)
setDepartmentSelected(numArr);
break;
}
}
const handleSelectFile = (event: any) => {
console.log(event.target.files[0]);
setSelectedFile(event.target.files[0]);
}
const handleCancelAction = () => {
history.push('/master-data/manage-book')
}
useEffect(() => {
console.log(authorSelected)
console.log(genreSelected)
console.log(departmentSelected)
}, [authorSelected, genreSelected, departmentSelected])
return (
<div className="form-create-book">
<Header>Update book</Header>
{
isLoading && (
<Wrapper style={{ padding: '40px 0' }}>
<Dimmer inverted active={true}>
<Loader>Loading</Loader>
</Dimmer>
</Wrapper>)
}
{
!isLoading && (
<div>
<Modal
size={"tiny"}
open={isOpen}
>
<Modal.Content>
<h2 style={{textAlign: 'center'}}>{alertText}</h2>
</Modal.Content>
<Modal.Actions>
{!isFailed &&
<Button negative onClick={() => setIsOpen(false)}>
Close
</Button>
}
<Button positive onClick={() => history.push("/librarian/master-data/manage-book")}>
Ok
</Button>
</Modal.Actions>
</Modal>
<Form className="create-book-form" onSubmit={handleSubmit(handleSubmitBtn)}>
<Form.Field>
<label className='dot-required'>Title</label>
<input {...register('title')} className="text-field" />
<p>{errors.title?.message}</p>
</Form.Field>
<Form.Field>
<label>Description</label>
<textarea {...register('description')} className="textarea-field" />
<p>{errors.description?.message}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>Publish Year</label>
<input className="text-field" {...register('publishYear')} />
<p>{errors.publishYear?.message}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>PDF File</label>
<input {...register('file')} className="text-field" accept="application/pdf" type="file" name="file" onChange={handleSelectFile} />
<p>{errors.file?.message}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>Access Permission</label>
<select defaultValue={book.isPublic ? 1 : 0} className="text-field" {...register('isPublic')}>
<option value={1}>Public</option>
<option value={0}>Restricted</option>
</select>
<p>{errors.isPublic?.message}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>Publisher</label>
<select className="text-field" {...register('publisherID')} >
{
publishers.map((e) => {
if (e.id === book.publisher.id)
return (<option selected value={e.id}>{e.name}</option>)
else
return (<option value={e.id}>{e.name}</option>)
}
)
}
</select>
<p>{errors.publisherID?.message}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>Authors</label>
<Dropdown className="text-field" onChange={(e, data) => handleAddItem(data, "AUTHOR")} placeholder='Authors' fluid multiple selection options={authorOptions} defaultValue={defaultAuthors} />
<p>{errMessage.type == "AUTHOR" ? errMessage.message : ''}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>Genre</label>
<Dropdown className="text-field" onChange={(e, data) => handleAddItem(data, "GENRE")} placeholder='Genres' fluid multiple selection options={genreOptions} defaultValue={defaultGenres} />
<p>{errMessage.type == "GENRE" ? errMessage.message : ''}</p>
</Form.Field>
<Form.Field>
<label className='dot-required'>Department</label>
<Dropdown className="text-field" onChange={(e, data) => handleAddItem(data, "DEPARTMENT")} placeholder='Genres' fluid multiple selection options={departmentOptions} defaultValue={defaultDepartments} />
<p>{errMessage.type == "DEPARTMENT" ? errMessage.message : ''}</p>
</Form.Field>
<Button
content="Submit"
// onClick={handleSubmit(handleSubmitBtn)}
className="ui inverted green button"
/>
<Button
color="black"
content="Cancel"
onClick={() => handleCancelAction()}
className="negative ui button"
/>
</Form>
</div>
)
}
</div>
);
};
export default UpdateBookPage;
When I check the source tab, I find out that the problem comes from here:
But I don't know how to solve it.
replace
.required("A random message")
.nullable(false)
to
.test("fileLength", "A random message", (value) => {
return !!value.length
})

How do I retrieve the selected value from a dropdown menu in ReactJS

I'm trying to get the value from the selected item of two drop down menu (DDM). The first DDM will populate the second DDM base on user input. E.g. first DDM select "langauge", second DDM will only show "c++, java, python, c#". I'm having difficulty in retrieving the value from both drop down menu as string ? Any suggestions ? Many thanks.
Current Code
/** Function that will set different values to state variable
* based on which dropdown is selected
*/
const changeSelectOptionHandler = (event) => {
setSelected(event.target.value);
};
/** Different arrays for different dropdowns */
const algorithm = [
"Searching Algorithm",
"Sorting Algorithm",
"Graph Algorithm",
];
const language = ["C++", "Java", "Python", "C#"];
const dataStructure = ["Arrays", "LinkedList", "Stack", "Queue"];
/** Type variable to store different array for different dropdown */
let type = null;
/** This will be used to create set of options that user will see */
let options = null;
/** Setting Type variable according to dropdown */
if (selected === "Algorithm") {
type = algorithm;
} else if (selected === "Language") {
type = language;
} else if (selected === "Data Structure") {
type = dataStructure;
}
/** If "Type" is null or undefined then options will be null,
* otherwise it will create a options iterable based on our array
*/
if (type) {
options = type.map((el) => <option key={el}>{el}</option>);
}
return (
<div>
<form>
<div>
{/** Bind changeSelectOptionHandler to onChange method of select.
* This method will trigger every time different
* option is selected.
*/}
<select onChange={changeSelectOptionHandler}>
<option>Choose...</option>
<option>Algorithm</option>
<option>Language</option>
<option>Data Structure</option>
</select>
</div>
<div>
<select>
{
options
}
</select>
</div>
</form>
</div>
);
};
export default App;
Try this approach,
import { useEffect, useState } from "react";
export default function App() {
const [selected, setSelected] = useState("");
const [type, setType] = useState([]);
const [selected2, setSelected2] = useState("");
const algorithm = [
"Searching Algorithm",
"Sorting Algorithm",
"Graph Algorithm"
];
const language = ["C++", "Java", "Python", "C#"];
const dataStructure = ["Arrays", "LinkedList", "Stack", "Queue"];
const changeSelectOptionHandler = (event) => {
setSelected(event.target.value);
};
const changeDp2Handle = (event) => {
setSelected2(event.target.value);
};
useEffect(() => {
let type = [];
if (selected === "Algorithm") {
type = algorithm;
} else if (selected === "Language") {
type = language;
} else if (selected === "Data Structure") {
type = dataStructure;
}
setSelected2("");
setType(type);
}, [selected]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<div>
<select onChange={changeSelectOptionHandler}>
<option>Choose...</option>
<option>Algorithm</option>
<option>Language</option>
<option>Data Structure</option>
</select>
</div>
<hr />
<div>
<select onChange={changeDp2Handle}>
<option>Choose...</option>
{type.map((v) => (
<option key={v}>{v}</option>
))}
</select>
{selected2}
</div>
</div>
);
}
codesandbox - https://codesandbox.io/s/jovial-resonance-joqlo?file=/src/App.js:0-1208
I would suggest to do something like so
import { useState } from "react";
import "./styles.css";
const Select = ({ options, fieldName }) => {
const [value, setValue] = useState();
return (
<select
name={fieldName}
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
>
{options.map(({ value, label }, i) => {
return (
<option key={i} value={value}>
{label}
</option>
);
})}
</select>
);
};
const dataStructureOptions = [
{
label: "Arrays",
value: "Arrays"
},
{
label: "LinkedList",
value: "LinkedList"
},
{
label: "Stack",
value: "Stack"
},
{
label: "Queue",
value: "Queue"
}
];
const languageOptions = [
{
label: "C++",
value: "C++"
},
{
label: "Java",
value: "Java"
},
{
label: "Python",
value: "Python"
},
{
label: "C#",
value: "C#"
}
];
const filterOptions = [
{
label: "Choose...",
value: "Choose..."
},
{
label: "Algorithm",
value: "Algorithm"
},
{
label: "Language",
value: "Language"
},
{
label: "Data Structure",
value: "Data Structure"
}
];
const mappedSelectedOptions = {
Language: languageOptions,
"Data Structure": dataStructureOptions
};
const FILTER_FIELD_NAME = "filter";
export default function App() {
const [currentSelectedFilter, setCurrentSelectedFilter] = useState();
const onFormChange = (e) => {
const fieldName = e.target.name;
if (fieldName === FILTER_FIELD_NAME) {
setCurrentSelectedFilter(e.target.value);
}
};
const onSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
console.log("onSubmit", formData);
};
const currentMappedOptions = mappedSelectedOptions[currentSelectedFilter];
return (
<div>
<form onChange={onFormChange} onSubmit={onSubmit}>
<Select options={filterOptions} fieldName={FILTER_FIELD_NAME} />
{currentMappedOptions && (
<Select options={currentMappedOptions} fieldName="options" />
)}
<button>Submit</button>
</form>
</div>
);
}

How can I react to a checkbox in a map?

How can I toggle a checkbox in a map when I click on it?
So only set to true or false which one was clicked.
Then I would like to either pack the value of the checkbox, in this case the index, into an array or delete it from it.
const handleChange = (event) => {
const copy = teilen;
setChecked(event.target.checked);
if (event.target.checked)
{
setTeilen(teilen, event.target.value);
} else {
copy.splice(event.target.value, 1);
setTeilen(copy);
}
console.log(teilen);
};
[...]
pdfs.map((p, index) => (
[...]
<Checkbox
value={p._id}
index={p._id}
checked={checked}
onChange={handleChange}
inputProps={{ "aria-label": "primary checkbox" }}
/>
[...]
))}
in your case you can try something like this:
const checkboxes = [
{
name:"a",
value:"a",
checked:false
},
{
name:"b",
value:"b",
checked:false
},
{
name:"c",
value:"c",
checked:false
},
];
const checkedArray = [];
const handleChange = (e) => {
if(e.target.checked){
checkedArray.push(item.value);
checkboxes[i].checked = true;
} else {
if(checkedArray.contains(item.value)){
checkedArray.filter(arrItem => arrItem === item.value);
}
checkboxes[i].checked = false;
}
const render = () => {
return checkboxes.map((item,i) => (
<input type="checkbox"
value={item.value}
name={item.value}
checked={item.checked}
onChange={handleChange}
/>
))
}
and you must keep the data in state to make component re-render.

Resources