Unable to Edit Multi Input fields with React useState - reactjs

I am new to react, i have an data object displaying it as form input default values.I need to update the object with input entry values. However i am able to edit only the first input field, but not other input fields. Could anyone help me what i am missing here.
Thank You
import { useState } from "react";
let userData = {
name: "Sample",
location: {
city: "Hyd",
population: "10000"
}
};
export default function App() {
const [data, setData] = useState(userData);
const handleChange = (event) => {
const name = event.target.name;
const value = event.target.value;
setData(previousState => {
return { ...previousState, [name]: value }
})
};
const handleSubmit = (e)=>{
e.preventDefault();
console.log(data);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<form>
<div>
<label>
Enter Your Name:
<input
type="text"
name="name"
value={data.name || ""}
onChange={handleChange}
/>
</label>
</div>
<div>
<label>
Enter Your City:
<input
type="text"
name="city"
value={data.location.city || ""}
onChange={handleChange}
/>
</label>
</div>
<div>
<label>
Enter Population:
<input
type="text"
name="population"
value={data.location.population || ""}
onChange={handleChange}
/>
</label>
</div>
<div>
<input type="submit" value="Submit" onClick={handleSubmit}/>
</div>
</form>
</div>
);
}

the problem is that you’re saving the city and population inside location object and when you set the state your function doesn’t recognize the location object.
one solution is that you have a flat state object like this
let userData = {
name: "Sample",
city: "Hyd",
population: "10000"
};
another solution is to check if the name is city or population pass the new value inside location object

Related

using useState to change get the input:text and using onclick to print new <p>

i'm a beginner in React and trying to learn useState. and I have difficulties on how to get the value of input and to save the value and print it on button click
const HomePage = () => {
const [state, setState] = useState({
Name: "",
surName: "",
});
const handleChange = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
const RenderNameOC = () => {
return (
<p>
Halo {Name} {surName}
</p>
);
};
return (
<DivContainer>
<ContainerTitle>
<p>Exercise 2 - Form</p>
</ContainerTitle>
<InputContainer>
<InputArea>
<label>Name: </label>
<input type="text" value={state.Name} onChange={handleChange} />
</InputArea>
<InputArea>
<label>Surname: </label>
<input type="text" value={state.surName} onChange={handleChange} />
</InputArea>
<SubmitButton onClick={RenderNameOC}>Submit</SubmitButton>
</InputContainer>
</DivContainer>
);
};
export default HomePage;
this is my code right now and the error it gave me was 'name' and 'surname' is not defined.
my expected result is that there will be 2 input textbox with for name and surname. and when the button is clicked, it will add a new <p> below it.
Here should be state.Name and state.surName
<p>
Halo {state.Name} {state.surName}
</p>
And add name in both inputs
<input
type="text"
name="Name"
value={state.Name}
onChange={handleChange}
/>
<label>Surname: </label>
<input
type="text"
name="surName"
value={state.surName}
onChange={handleChange}
/>
But no point of returning anything RenderNameOC since onClick is a void function. Just move this template below the submit button
Demo

Passing values between components in React

I m beginner to reactJS and I m having so much trouble with self learning.
I want to print the data I get from first page.
I used 2 .js files
This is userpage.js:
import resultPage from "./resultPage";
// JS
//const input = document.getElementById('myText');
//const inputValue = input.value
// React
// value, onChange
const Multi = () => {
const [person, setPerson] = useState({ firstName: "", email: "", age: "" });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
//e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: "", email: "", age: "" });
resultPage(people, person);
}
};
return (
<>
<article className="form">
<form>
<div className="form-control">
<label htmlFor="firstName">Name : </label>
<input
type="text"
id="firstName"
name="firstName"
value={person.firstName}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="email">Email : </label>
<input
type="email"
id="email"
name="email"
value={person.email}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="age">Age : </label>
<input
type="number"
id="age"
name="age"
value={person.age}
onChange={handleChange}
/>
</div>
<button type="submit" className="btn" onClick={handleSubmit}>
add person
</button>
</form>
</article>
</>
);
};
export default Multi;
This has 2 textboxes and a submit button.
This code is from resultPage.js:
function resultPage(people, person) {
return (
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className="item">
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
);
}
export default resultPage;
What am I doing wrong? I m new to reactjs. So kindly spare my obvious mistakes and help me.
From React documentation
HTML form elements work a bit differently from other DOM elements in React, because form elements naturally keep some internal state.
You need to add handleSubmit to your form, and it'll work. As #Halcyon suggested, using a Capital case for a component is good. It's tough to distinguish between HTML elements and components if you use lowercase. Read this for more details.
I am attaching a working sandbox for your code.
You're calling resultPage in handleSubmit. That's not going to work. You want resultPage to be part of the rendering, probably conditionally.
Consider something like:
return <>
{person.firstName !== "" && <resultPage people={people} person={person} />}
{person.firstName === "" && <>
// the form
</>}
</>;
Also since resultPage is a component, it's best to capitalize it.
I think you probably want a 3rd component:
const MyComponent = () => {
const [ people, setPeople ] = React.useState([]);
const [ isEditing, setIsEditing ] = React.useState(false);
return <>
{isEditing && <Multi setPeople={(people) => {
setPeople(people);
setIsEditing(false);
}}
{isEditing === false && <resultPage people={people} />}
</>;
}
Mutli now accepts a prop setPeople that is called in handleSubmit.

Is there any way of creating a component with images based on user input?

I am trying to let the user input a image that i later can display in another component, It is supposed to be displayed inside my "Card" component which is displayed inside my "Grid" component. The grid component then maps and displays all the houses in the "houses" array which also is a separate component. Manually creating houses inside the array works perfectly but when the user is trying to add a house everything but the images works. The console log in submitListing will show that the houses beeing added does contain an image but it is not beeing displayed in the grid. (Also, the first house that is submitted only contains an empty array for mainImg but the rest contains the "blob" image) Entire project: https://codesandbox.io/s/relaxed-orla-fqcwoy?file=/src/components/header/AddListing.jsx
HTML
<textarea
value={listing.area}
name="area"
onChange={handleChange}
className="area"
></textarea>
<input
onChange={handleInputChange}
name="mainImg"
type={"file"}
></input>
JS
const [listing, setListing] = useState({
area: "",
mainImg: [],
});
function handleChange(e) {
const { name, value } = e.target;
setListing((previousListing) => {
return { ...previousListing, [name]: value };
});
}
const [file, setFile] = useState();
function handleInputChange(e) {
setFile(URL.createObjectURL(e.target.files[0]));
}
function submitListing(e) {
e.preventDefault();
setListing({
area: "",
mainImg: file,
});
houses.push(listing);
console.log(houses);
}
So, here are the issues. I might forget something but i forked codesandbox, so you will be able to compare.
In your houses.js and AddListing.jsx you had mainImage and mainImg. You need to have a strict structure and naming, they had to match.
const [file, setFile] was.. useless, you had to save blobs into the listing object itself in the mainImage, img2, etc.
About the structure again. You had your mainImg, img2, ... set to an empty array, []. That have no sense due to you dont use <input type="file" multiple>. Switched them to undefined / string.
You cannot really bind value to the input type=file in react. Just remove the value from inputs.
Be careful with useEffects and useState's setValues, without understanding how they work it is really easy to make a mistake.
Here is your updated and working AddListing.jsx
import React, { useState, useCallback, useEffect } from "react";
import "./AddListing.css";
import houses from "../../houses";
const getDefaultListing = () => {
return {
id: houses.length + 1,
area: "",
state: "",
shortDesc: "",
longDesc: "",
pricePerNight: "",
cleaningFee: "",
serviceFee: "",
mainImage: undefined,
img2: undefined,
img3: undefined,
img4: undefined,
img5: undefined
};
};
function AddListing() {
const [listing, setListing] = useState(() => getDefaultListing());
const handleChange = useCallback((e) => {
const { name, value } = e.target;
setListing((prev) => ({ ...prev, [name]: value }));
}, []);
const handleInputChange = useCallback((e) => {
const { name, files } = e.target;
const [singleImage] = files;
if (!singleImage) {
setListing((prev) => ({ ...prev, [name]: undefined }));
} else {
const blob = URL.createObjectURL(singleImage);
setListing((prev) => ({ ...prev, [name]: blob }));
}
}, []);
const submitListing = useCallback(
(e) => {
e.preventDefault();
houses.push(listing);
setListing(() => getDefaultListing());
console.log(houses);
},
[listing]
);
useEffect(() => {
console.log(listing);
}, [listing]);
return (
<div className="add-listing-div">
<form>
<p id="p1">State</p>
<p id="p2">Area</p>
<textarea
value={listing.state}
name="state"
onChange={handleChange}
className="state"
/>
<textarea
value={listing.area}
name="area"
onChange={handleChange}
className="area"
/>
<p id="p3">Short Description</p>
<textarea
value={listing.shortDesc}
name="shortDesc"
onChange={handleChange}
className="short-description"
/>
<p id="p4">Long Description</p>
<textarea
value={listing.longDesc}
name="longDesc"
onChange={handleChange}
className="long-description"
/>
<p id="p5">Price/Night</p>
<p id="p6">Cleaning Fee</p>
<p id="p7">Service Fee</p>
<textarea
value={listing.pricePerNight}
name="pricePerNight"
onChange={handleChange}
className="price-per-night"
/>
<textarea
value={listing.cleaningFee}
name="cleaningFee"
onChange={handleChange}
className="cleaning-fee"
/>
<textarea
value={listing.serviceFee}
name="serviceFee"
onChange={handleChange}
className="service-fee"
/>
<label>Main Image: </label>
<input onChange={handleInputChange} name="mainImage" type="file" />
<label>Second Image: </label>
<input onChange={handleInputChange} name="img2" type="file" />
<label>Third Image: </label>
<input onChange={handleInputChange} name="img3" type="file" />
<label>Fourth Image: </label>
<input onChange={handleInputChange} name="img4" type="file" />
<label>Fifth Image: </label>
<input onChange={handleInputChange} name="img5" type="file" />
<button onClick={submitListing}>Submit</button>
</form>
</div>
);
}
export default AddListing;

How to make input field text editable?

I have a problem of trying to make the input text field editable.
Currently, I am unable to edit the values of the input text field where i can remove or add new characters to the value in the input text field.
I have set the values statically in the state objects but I also want to edit the state values from the input text field.
How can I edit the code below to make the value editable?
import React, { Component } from 'react';
import { render } from 'react-dom';
class Info extends Component {
constructor(props) {
super(props);
this.state = {
name: "Jack Sparrow",
age: "52",
email: "jacksparrow52#gmail.com"
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let newState = {...this.state};
newState[e.target.name] = e.target.name
this.setState({
...newState
})
}
render() {
return (
<div>
<input type="text" name="name" value={this.state.name} placeholder="Enter your name..." onChange={(e) => this.handleChange(e)} />
<br /> <br />
<input type="text" name="age" value={this.state.age} placeholder="Enter your age..." onChange={(e) => this.handleChange(e)} />
<br /> <br />
<input type="text" name="email" value={this.state.email} placeholder="Enter your email..." onChange={(e) => this.handleChange(e)} />
<h3>Output states:</h3>
<p id="name">Entered Name: {this.state.name}</p>
<p id="age">Entered Age: {this.state.age}</p>
<p id="email">Entered Email: {this.state.email}</p>
</div>
);
}
}
render(<Info />, document.getElementById('root'));
You are setting the state to the target input name. Fix this line
newState[e.target.name] = e.target.name
with (notice e.target.value)
newState[e.target.name] = e.target.value
Change your input field like this, Add input field name and bind handle Change inside the input field. Now you do not want to bind handle Change in constructor.
<input type="text" name="name" value={this.state.name} placeholder="Enter your name..." onChange={this.handelChange.bind(this, 'name')} />
Now replace handle change function,
handelChange(field, event) {
this.setState({
[field]: event.target.value
})
}
I hope this helps, I created a codesandbox with this solution
https://codesandbox.io/s/editable-inputs-m4fqk6?file=/src/App.tsx:256-2201
import { useState } from "react";
interface infoProfile {
name: string;
email: string;
}
const App = () => {
const [editCancel, setEditCancel] = useState(false);
const [value, setValue] = useState<infoProfile>({
name: "Anakin Skywalker",
email: "anakin#empire.com"
});
const onClick = (): void => {
setValue({ email: value.email, name: value.name });
setEditCancel(false);
};
return (
<>
<h1>Editable Inputs</h1>
<div>
<button onClick={() => setEditCancel(!editCancel)}>
{editCancel ? "Cancel" : "Edit"}
</button>
{editCancel && <button onClick={onClick}>Save</button>}
</div>
{!editCancel && (
<div>
<h2>Name</h2>
<div>{value.name}</div>
<h2>Email</h2>
<div>{value.email}</div>
</div>
)}
{editCancel && (
<div>
<h2>Name</h2>
<input
value={value.name}
onChange={(e) =>
setValue({ name: e.target.value, email: value.email })
}
/>
<h2>Email</h2>
<input
value={value.email}
onChange={(e) =>
setValue({ email: e.target.value, name: value.name })
}
/>
</div>
)}
</>
);
};
export default App;

How can I view data after fetching the data on the console log in api?

I'm starting to learn reactjs and I want to view the data on the table after I input text on the input fields and show the data on a console log. How can I show all the data input to the page?
onAdd(employee_name, employee_age, employee_salary){
console.log(employee_name, employee_age, employee_salary);}
I expect to show the data input in the input fields in the page. Thank you
This should work:
import React, { Component } from 'react';
class EmployeeInput extends Component {
state = {
employee_name: '',
employee_age: '',
employee_salary: '',
};
handleChange = e => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
render() {
return (
<form>
<div>
<label>
employee_name
<input name="employee_name" type="text" onChange={this.handleChange} />
</label>
Value: {this.state.employee_name}
</div>
<div>
<label>
employee_age
<input name="employee_age" type="text" onChange={this.handleChange} />
</label>
Value: {this.state.employee_age}
</div>
<div>
<label>
employee_salary
<input name="employee_salary" type="text" onChange={this.handleChange} />
Value: {this.state.employee_salary}
</label>
</div>
</form>
);
}
}
Here's a running example: https://stackblitz.com/edit/react-jl2skw?file=index.js

Resources