How to fetch option value from select in React - reactjs

I'm looking for a way to get option value from select.
Main point for this is that i want to get value from select and then display different car from carArray.
I'm still learning react so please just tell me which way i should go.
My code:
import React, { useState } from 'react'
const UserCar = () => {
const carArray = [
{id: 1,name: "Opel Astra", brand: "Opel", model: "Astra J ST SPORT 2.0 CDTI", plate: "KGR XXX"},
{id: 2,name: "Opel Frontera", brand: "Opel", model: "Frontera 2.2DTI 4x4", plate: "KGR XXX1"},
{id: 3,name: "Peugeot 207", brand: "Peugeot 207", model: "Peugeot 207 1.4", plate: "KGR XXX2"},
]
const handleChange = (event) => {
const aaa = this.setState({value: event.target.value});
console.log(aaa);
}
return (
<div>
<select onChange={handleChange}>
{
carArray.map(function(element){
return(
<option value={element.name}> {element.name}</option>
)
})
}
</select>
/*****\/ Here i want to display car details depend on which one option is selected *****/
<form>
<fieldset disabled>
<legend>Twój samochód: </legend>
<div class="mb-3">
<label for="disabledTextInput" class="form-label">Marka Pojazdu</label>
<input type="text" id="disabledTextInput" class="form-control" placeholder="Opel" />
</div>
<div class="mb-3">
<label for="disabledTextInput" class="form-label">Model Pojazdu</label>
<input type="text" id="disabledTextInput" class="form-control" placeholder="Astra J ST SPORT 2.0 CDTI " />
</div>
<div class="mb-3">
<label for="disabledTextInput" class="form-label">Rejestracja</label>
<input type="text" id="disabledTextInput" class="form-control" placeholder="KGR XXX" />
</div>
</fieldset>
<button type="submit" class="btn btn-primary m-4 float-end">Zmień</button>
</form>
</div>
)
}
export default UserCar

There are several problems with your JSX code.
1. JSX syntax
HTML attribute for should be replaced with htmlForm.
HTML attribute class should be replaced with className.
2. In the functional component, you need to use useState hook instead of this.setState.
3. Correct implementation.
Define state variable to store the selected car info.
const [selectedCar, setSelectedCar] = useState();
In OnChange function in select element, you will update the selectedCar state variable.
setSelectedCar(carArray.find((ele) => event.target.value == ele.id));
Your component UserCar should look like the following.
const UserCar = () => {
const [selectedCar, setSelectedCar] = useState<any>();
const carArray = [Your car array];
const handleChange = (event) => {
setSelectedCar(carArray.find((ele) => event.target.value == ele.id));
};
return (
<div>
<select onChange={handleChange}>
{carArray.map((element) => {
return (
<option key={element.id} value={element.id}>
{element.name}
</option>
);
})}
</select>
{selectedCar && (
<div>
{selectedCar.name}, {selectedCar.brand}, {selectedCar.model}
</div>
)}
<form>
...
</form>
</div>
);
};

Related

Edit Data in Parent from Child

Apparently I'm not doing this right, but I'm trying to mutate a map in the parent component from a child component in React 18.2. The parent contains a modal which opens a form. The user then inputs their mutate option (delete/add) and subsequent data from there. I've been going through other questions trying to find an answer for why it's not working as intended, but I can't seem to find much info. Would appreciate any help. This is what I currently have:
Parent.Js
const ParentComponent = ({show, onCloseModalButton}) => {
const resorts = new Map()
resorts.set("Keystone", [39.6069742, -105.97011])
resorts.set("Breckenridge", [39.4808, -106.0676])
resorts.set("Vail", [39.6061, -106.3550])
resorts.set("Crested Butte", [38.8991, -106.9658])
resorts.set("Winter Park", [39.8841, -105.7627])
resorts.set("Copper Mountain", [39.5022, -106.1497])
const [formOption, setFormOption] = React.useState("")
const [formData, setFormData] = React.useState({
resortName: "",
longitude: Number,
latitude: Number,
})
const handleOptionChange = e => {
setFormOption(e.target.value)
}
const handleFormDataChange = e => {
setFormData({
...formData,
[e.target.name]: e.target.value,
})
}
const submitForm = e => {
e.preventDefault()
if (formOption === "Add") {
resorts.set(formData.resortName, [formData.latitude, formData.longitude])
}
if (formOption === "Delete") {
resorts.delete(formData.resortName)
}
}
return (
<div>
<Modal show={show} onCloseModalButton={onCloseModalButton} resorts={resorts} submitForm={submitForm} handleOptionChange={handleOptionChange} handleFormChange={handleFormDataChange} option={formOption} form={formData} />
</div>
)
}
export default ParentComponent;
Modal.js
const Modal = ({show, onCloseModalButton, resorts, submitForm, handleOptionChange, handleFormChange, option, form}) => {
if (!show) {
return null
}
return ReactDOM.createPortal (
<div className='modal-bg'>
<div className='modal'>
<form onSubmit={submitForm}>
<label>Modify:
<select
name="option"
value={option}
onChange={handleOptionChange}
>
<option value="" disabled={true}>-- Choose an Option --</option>
<option value="Add">Add</option>
<option value="Delete">Delete</option>
</select>
</label>
{option === "" ? null :
option === "Add" ?
<div>
<label>Resort Name
<input
type="text"
name="resortName"
value={form.resortName}
onChange={handleFormChange}
/>
</label>
<br></br>
<label>Longitude
<input
type="number"
name="longitude"
value={form.longitude}
onChange={handleFormChange}
/>
</label>
<br></br>
<label>Latitude
<input
type="number"
name="latitude"
value={form.latitude}
onChange={handleFormChange}
/>
</label>
<button type='submit'>Submit</button>
</div> :
<div>
<label>Delete
<select
name="delete"
value={form.resortName}
onChange={handleFormChange}
>
{[...resorts.keys()].map((item)=> {
return <option key={item} value={item}>{item}</option>
})}
</select>
</label>
<button type='submit'>Submit</button>
</div>
}
</form>
<button onClick={onCloseModalButton}>Close Modal</button>
</div>
</div>
, document.body
)
}
export default Modal;

What is an efficient way of handling Child Component States from a Parent Component map?

I want to have a Parent component which can add a number of Child components - pressing a button will add a new Child Object to state, which subsequently renders the Child component through a children.map(c => ...) function.
Child is a component that renders a dropdown menu to select an option - based on the selected option, additional inputs appear (e.g. 'Person' renders 'First Name', 'Last Name'). The user should be able to add multiple Child components, and update them easily. The problem I have is value/state storage:
Storing the values of each Child component in the Parent is easy to do, but the state will reupdate every child due to the children.map render method. This would happen on each key-press/value change etc.
I recognise it is bad practice to store Components in state, so have tried rendering these through the objects.
There could be any number of Child components (1, 5, 100...)
Example files:
Parent.jsx:
import React, { useState } from "react";
import Child from "./Child";
const Parent = () => {
/**
* This should be an array of objects:
*
* {
* childType: person | animal | city,
* values: (one of the below)
* }
*
* personValue: {
* firstName: string
* lastName: string
* }
*
* animalValue: {
* animalType: string;
* age: number
* }
*
* cityValue: {
* name: string
* population: number
* }
*
*/
const [children, setChildren] = useState([]);
const defaultChild = {
childType: "",
childId: Math.random(),
values: {},
};
const addChild = () => {
setChildren([...children, defaultChild]);
};
const handleUpdateChildType = (childId, newChildType) => {
let newChildren = [...children];
let childIndex = children.findIndex((f) => f.childId === childId);
let child = children[childIndex];
child.childType = newChildType;
newChildren[childId] = child;
setChildren(newChildren);
};
const handleUpdateChildValues = (childId, field, newValue) => {
let newChildren = [...children];
let childIndex = children.findIndex((f) => f.childId === childId);
let child = children[childIndex];
child.values[field] = newValue;
newChildren[childId] = child;
setChildren(newChildren);
};
return (
<div className="parent">
<div>
<h2>Parent</h2>
<button onClick={addChild}>Add Child</button>
</div>
<div>
{children.map((child) => (
<Child
childId={child.childId}
childType={child.childType}
values={child.values}
updateChildType={handleUpdateChildType}
updateChildValues={handleUpdateChildValues}
/>
))}
</div>
</div>
);
};
export default Parent;
Child.jsx:
import React from "react";
const Child = (props) => {
const { childId, childType, values, updateChildType, updateChildValues } =
props;
console.log(`Child ${childId} rerendering...`);
const handleChildTypeChange = (e) => {
updateChildType(childId, e.target.value);
};
const handleChildValuesChange = (field, newValue) => {
updateChildValues(childId, field, newValue);
};
return (
<div>
<h3>Child</h3>
<div>
<div>
<label htmlFor="childType">Choose an option</label>
<select
name="childType"
id={`${Math.random()}`}
onChange={handleChildTypeChange}
value={childType}
>
<option value="person">person</option>
<option value="animal">animal</option>
<option value="city">city</option>
</select>
</div>
<div>
{childType === "person" ? (
<div>
<label htmlFor="firstName">First name:</label>
<input
type="text"
id="firstName"
name="firstName"
value={values.firstName}
onChange={(e) =>
handleChildValuesChange("firstName", e.target.value)
}
></input>
<label htmlFor="lastName">Last name:</label>
<input
type="text"
id="lastName"
name="lastName"
value={values.lastName}
onChange={(e) =>
handleChildValuesChange("lastName", e.target.value)
}
></input>
</div>
) : childType === "animal" ? (
<div>
<label htmlFor="animalType">Animal Type:</label>
<input
type="text"
id="animalType"
name="animalType"
value={values.animalType}
onChange={(e) =>
handleChildValuesChange("animalType", e.target.value)
}
></input>
<label htmlFor="age">Age:</label>
<input
type="number"
id="age"
name="age"
value={values.age}
onChange={(e) => handleChildValuesChange("age", e.target.value)}
></input>
</div>
) : childType === "city" ? (
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
name="name"
value={values.name}
onChange={(e) =>
handleChildValuesChange("name", e.target.value)
}
></input>
<label htmlFor="population">Population:</label>
<input
type="number"
id="population"
name="population"
value={values.population}
onChange={(e) =>
handleChildValuesChange("population", e.target.value)
}
></input>
</div>
) : null}
</div>
</div>
</div>
);
};
export default Child;
Edit: The Parent component requires the state as additional logic would be included in it, such as validating the object and making an API call with the generated state. I've omitted these from the code to keep the code compact.

The input value codes refused to work in react js

What could be wrong with these codes? The input is not working once I add [event.target.name]. If I remove that line of codes, I can see the contents that I type inside the input box. The issue is that I want it to work with this code [event.target.name]. This will enable me pick each inputbox values as entered by the user. There are three input boxes and I need to capture the three values in my useState. Any help on how to write it better?
import React, { useState } from 'react';
import "./addbirthday.css";
import "./home.css";
export default function Addbirthday({setShowAdd}) {
const [inputDatas, setInputData] = useState([
{fullName: '', fullDate: '', relationship: ''}
]);
const handlePublish = () =>{
console.log("Hi ", inputDatas)
}
const handleChangeInput = (index, event) =>{
const values = [...inputDatas];
values[index][event.target.name] = event.target.value
setInputData(values)
}
return (
<div className="container">
<div className= { closeInput? "addContainer" :"addWrapper homeWrapper "}>
<i className="fas fa-window-close" onClick={closeNow} ></i>
{inputDatas.map((inputData, index)=> (
<div key={index} className="addbirth">
<label>Name</label>
<input type="text" name="Fname" placeholder='Namend' value=
{inputData.fullName} onChange = {event => handleChangeInput(index, event)} />
<label>Date</label>
<input type="date" placeholder='Date' name="fdate" value=
{inputData.fullDate} onChange = {event => handleChangeInput(index, event)} />
<label>Relationship</label>
<input type="text" placeholder='Friend' name="frelationship" value=
{inputData.relationship} onChange = {event => handleChangeInput(index, event)}/>
</div>
))}
<button className="addBtn" onClick={handlePublish} >Add</button>
</div>
</div>
)
}
You are not setting the name correctly
Change your input tags name to same as state object name meaning
<input name='fullname' />
I have modified your code a bit. Make it as your own and get it done
Upvote my answer if it helps
https://codesandbox.io/s/jolly-khayyam-51ybe?file=/src/App.js:0-1711
import React, { useState } from "react";
export default function Addbirthday({ setShowAdd }) {
const [inputDatas, setInputData] = useState([
{ Fname: "", fdate: "", frelationship: "" }
]);
const handlePublish = () => {
console.log("Hi ", inputDatas);
};
const handleChangeInput = (index, event) => {
const values = [...inputDatas];
values[index][event.target.name] = event.target.value;
setInputData(values);
console.log(values[index][event.target.name]);
};
return (
<div className="container">
<div className={"addContainer addWrapper homeWrapper"}>
<i className="fas fa-window-close"></i>
{inputDatas.map((inputData, index) => (
<div key={index} className="addbirth">
<label>Name</label>
<input
type="text"
name="Fname"
placeholder="Namend"
value={inputData.fullName}
onChange={(event) => handleChangeInput(index, event)}
/>
<label>Date</label>
<input
type="date"
placeholder="Date"
name="fdate"
value={inputData.fullDate}
onChange={(event) => handleChangeInput(index, event)}
/>
<label>Relationship</label>
<input
type="text"
placeholder="Friend"
name="frelationship"
value={inputData.relationship}
onChange={(event) => handleChangeInput(index, event)}
/>
</div>
))}
<button className="addBtn" onClick={handlePublish}>
Add
</button>
</div>
</div>
);
}

Unable to type in input field React

I am creating a simple todo list. In here there is a modal for the update form,I can take the relevant values from the state And set them to the input field values. then I can't edit the input fields. I think the problem is with the onChange function or value property
import React from 'react'
import {useRef,useState,useEffect} from 'react'
import {FaTimes} from 'react-icons/fa'
export const Modal = ({edData,showModal,setShowModal,onAdd,setEd,tasks}) => {
const [text,setText] = useState('')
const[day,setDay] = useState('')
const[reminder,setReminder] = useState(false)
useEffect(() => {
if(edData!=null){
for(let i=0;i<tasks.length;i++)
{
if(tasks[i].id===edData){
// console.log(tasks[i])
setText(tasks[i].text)
setDay(tasks[i].day)
setReminder(tasks[i].reminder)
}
}
}
// inputText.current.value = edData.text;
// inputDay.current.value = edData.day;
// inputReminder.current.value = edData.reminder;
});
const closeModal = () =>{
setEd(null)
setShowModal(prev=>!prev)
setText('')
setDay('')
setReminder(false)
}
const onSubmit = (e) =>{
e.preventDefault()
if (!text){
alert('Please add a task')
return
}
onAdd({text,day,reminder})
setText('')
setDay('')
setReminder(false)
setShowModal(prev=>!prev)
}
return (
<>
{showModal?
<div className="background">
<div className="ModalWrapper" >
<div className="ModalContent">
<h2 className="modalTitle">{edData==null? 'Add New Task':'Update Task'}</h2>
<form className="add-form" onSubmit={onSubmit}>
<div className="form-control">
<label htmlFor="">Task</label>
<input type="text" placeholder="Add Task" name="" id="" value={text} onChange={(e) => setText(e.target.value)}/>
</div>
<div className="form-control ">
<label htmlFor="">Date & Time</label>
<input type="text" placeholder="Add Date and Time" name="" id="" value={day} onChange={(e) => setDay(e.target.value)}/>
</div>
<div className="form-control form-control-check">
<label htmlFor="">Set Reminder</label>
<input type="checkbox" checked={reminder} name="" id="" value={reminder} onChange={(e) => setReminder(e.currentTarget.checked)}/>
</div>
<input className="btn btn-block" type="submit" value="Save Task" />
</form >
</div>
<div className="CloseModalButton" onClick={closeModal}>
<FaTimes/>
</div>
</div>
</div>
: null}
</>
)
}
If you don't pass a dependency array to useEffect it will be called on every render, calling setText inside of it and overwriting the input's value, pass an empty array to useEffect if you don't want it to run on every render :
useEffect(() => {
// ....
}, []);

Clear form after submit React

In my app, I am making a form to add animal for adoption with React. The data is stored in Mongo if this is important to know.
But I can not figure out how, I tried to look and nothing works for me. Maybe there is something wrong with the form. I would be very thankful if someone can tell me how to clear or reset the form after submitting. I simplified it so it would be easy to see what I have. Here is my form:
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { addAnimal } from "../redux/actions";
const AddAnimalForm = () => {
const dispatch = useDispatch();
const [name, setName] = useState("");
const [kind, setKind] = useState("");
const [displayForm, setDisplayForm] = useState(false);
const dispatchAddAnimal = () => {
dispatch(
addAnimal(
{
name,
kind
},
"_id name kind sex age city author phone info"
)
);
};
const onShowButtonClicked = () => {
setDisplayForm(true);
};
const onHideButtonClicked = () => {
setDisplayForm(false);
};
return !displayForm ? (
<button className="col-xs-12 col-md-3" onClick={onShowButtonClicked}>
add
</button>
) : (
<React.Fragment>
<div className="col-xs-12 col-sm-9">
<button className="col-xs-12 col-md-3" onClick={onHideButtonClicked}>
hide{" "}
</button>
<form>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="animal-name">name</label>
<input
type="text"
className="form-control"
onChange={e => setName(e.target.value)}
id="animal-name"
/>
</div>
<div className="form-group col-md-6">
<label htmlFor="kind">kind</label>
<input
type="text"
onChange={e => setKind(e.target.value)}
className="form-control"
id="kind"
/>
</div>
</div>
<button
type="button"
className="btn btn-primary"
onClick={dispatchAddAnimal}
>
add animal
</button>
</form>
</div>
</React.Fragment>
);
};
export default AddAnimalForm;
define a variable at the top just below you imports
let exampleRef = React.createRef()
hi first you have to create a reference to that form like this :-
<form ref={(el) => myFormRef = el;}>
<input />
<input />
...
<input />
</form>
and after that, while submitting your form you just use the reset() method provided by the form reference like this
const dispatchAddAnimal = () => {
myFormRef.reset();
dispatch(
addAnimal(
{
name,
kind
},
"_id name kind sex age city author phone info"
)
);
};
let me know if it works for you or not.
there is also a great library React Advanced Form which handle lots of thing on its own like validation and other stuff check this out if you feel free

Resources