I can't seem to figure out why my form clears prev data when submitting. I have an edit button that when clicked pops open a form. If I edit the name field but not the birthdate field, the name is changed and the birthdate blanks out. It may be a simple silly error but a 2nd set of eyes may help
class Card extends Component {
constructor(props) {
super(props);
this.state = {
dataEditingMode: false,
planetSelection: this.props.homeWorld,
}
}
onEditDeets() {
this.setState({
dataEditingMode: !this.state.dataEditingMode
});
}
onSaveDeets(element) {
element.preventDefault();
this.props.onSavingEditedDeets(
this.props.id,
this.refs.personName.value,
this.refs.personBirthday.value,
this.refs.personHomeWorld.value)
this.setState({
dataEditingMode: false
});
}
onEditPlanetSelection(event) {
this.setState({
planetSelection:event.target.value
});
}
render() {
let getHomeWorld = (planetID) => {
for (var i = 0; i < this.props.planetList.length; i++) {
if (this.props.planetList[i].id === planetID) {
return this.props.planetList[i].name;
}
}
return 'planet does not exist.'
}
let name = this.props.name;
let imageURL = this.props.imageURL;
let birthday = this.props.birthday;
let homeWorld = this.props.homeWorld;
let dataEditingForm;
if (this.state.dataEditingMode === true) {
dataEditingForm = <form
onSubmit={this.onSaveDeets.bind(this)}>
<span>Name: </span>
<input type="text" ref="personName" />
<span>Birthday: </span>
<input type="text" ref="personBirthday" />
<span>Homeworld: </span>
<select
value={this.state.planetSelection}
ref="personHomeWorld"
onChange={this.onEditPlanetSelection.bind(this)}
>
{this.props.planetList.map((planet)=>{
return <option
key={planet.id}
value={planet.id}
>
{planet.name}
</option>
})}
</select>
<button>Save Deets</button>
</form>
} else {
dataEditingForm = <div></div>
}
return (
<div className='card'>
<div className='card-content'>
<div className='card-name'>{name}</div>
<img src={imageURL} alt='profile'/>
<p>
<span>Birthday:</span>
<span>{birthday}</span>
</p>
<p>
<span>Homeworld:</span>
<span>{getHomeWorld(homeWorld)}</span>
</p>
<p>
<span>
<button type="button" onClick={this.onEditDeets.bind(this)}>Edit Card Deets</button>
</span>
</p>
{dataEditingForm}
</div>
</div>
);
}
}
export default Card;
Basically, you are updating your state based on the values of the form, irrespective of whether they are changed or not.
For a simple change, you can just set the default value of your input tags to the state
<span>Name: </span>
<input type="text" ref="personName" defaultValue="{name}" />
<span>Birthday: </span>
<input type="text" ref="personBirthday" defaultValue="{birthday}"/>
Also, in this case, I prefer performing edits like this based on the form state but depending on the scenario you would want to handle onChange.
For example, in a settings page, you might want certain toggles to be effective immediately. Then you should handle onChange and update the state directly.
Related
I have an input wuth "ok" button on a page and I want to write a number in my input, then by pressing the button, Input tags should be prepared for me according to the amount of the number I had entered
For example, if I enter the number 4 in my input and then click the OK button, 4 input tags will be created for me.
How can I write this code in react js?
I tried the folloing code but it's not working... .
import {useState} from "react";
const makeInputComponent = () => {
const [numberOfProcess, setNumberOfProcess] = useState(null)
const returnInput = ()=>{
return <input type="text" />
}
const makeInput = () => {
for (let i = 0; i < Number(numberOfProcess); i++) {
returnInput()
console.log(i)
}
}
return (
<div>
<label> enter your number </label>
<input type="text" value={numberOfProcess} onChange={(event)=>setNumberOfProcess(event.target.value)} />
<button onClick={ makeInput } > ok </button>
</div>
)
}
export default makeInputComponent ;
You can try this code.
const [numInputs, setNumInputs] = useState(0)
const createInputs = () => {
const inputArray = []
for (let i = 0; i < numInputs; i++) {
inputArray.push(<input type="text" key={i} />)
}
return inputArray
}
return (
<div>
<input
type="number"
value={numInputs}
onChange={(e) => setNumInputs(+e.target.value)}
/>
<button onClick={createInputs}>OK</button>
{createInputs()}
</div>
)
Solution:
Here is what you can do, take the value from the input and when button is pressed with that input value create a array of that length and then map that array for creating input box.
export default function App() {
const[val,Setval]=useState("")
const[inputbox,Setinputbox]=useState([])
const handleClick=()=>{
const array=new Array(val*1).fill(0)
Setinputbox(array)
}
return (
<div className="App">
<input type="number" value={val} onChange={e=>Setval(e.target.value)}/>
<button onClick={handleClick}>Submit</button>
<div>
{inputbox.map((val,index)=>{
return(
<input key={index} type="text"/>
)
})}
</div>
</div>
);
}
I have a bug when I set the value from the state and change the value in a input.
when you write in the input and you try to correct the text the cursor move to the end.
This is my element
<div className="campo">
<p>Nombre</p>
<div className="campo-input">
<input
type="text"
name="name"
value={this.state.name}
onChange={this.handleInputChangeUpperCase}
/>
</div>
</div>
This is my function
handleInputChangeUpperCase = (e) => {
let { name, value } = e.target;
this.setState({ [name]: value.toUpperCase() });
};
Working Snippet:
class App extends React.Component {
state = {
name: "Ronaldo",
};
// This is the function
handleInputChangeUpperCase = (e) => {
let { name, value } = e.target;
this.setState({
[name]: value.toUpperCase(),
});
};
render() {
// This is the Element
return (
<div className="campo">
<p> Nombre </p>
<div className="campo-input">
<input
type="text"
name="name"
value={this.state.name}
onChange={this.handleInputChangeUpperCase}
/>
{this.state.name}
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Based on the original answer: https://stackoverflow.com/a/49648061/7427111
class App extends React.Component {
state = {
name: "Ronaldo",
};
handleInputChangeUpperCase = (e) => {
// Here is the addition
const pointer = e.target.selectionStart;
const element = e.target;
window.requestAnimationFrame(() => {
element.selectionStart = pointer;
element.selectionEnd = pointer;
});
let { name, value } = e.target;
this.setState({
[name]: value.toUpperCase(),
});
};
render() {
return (
<div className="campo">
<p> Nombre </p>
<div className="campo-input">
<input
type="text"
name="name"
value={this.state.name}
onChange={this.handleInputChangeUpperCase}
/>
{this.state.name}
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
To control where the cursor is in an input field, use selectionStart, which indicates where your selected text begins. As long as you don't set selectionEnd, you'll just move the cursor to the desired position.
For instance, let's move to the position "1", just after the first character. For input "123", that should be "1|23"...
document.getElementById('text-area').selectionStart = 1;
document.getElementById('text-area').focus()
<input id="text-area" type="text" value="123"/>
For your situation, if you want the cursor to move to the start of the string, set .selectionStart = 0. If you want it to go back to where it was originally, save the value with var tempstart = ...selectionStart, and then restore it after you do the data change, .selectionStart = tempstart.
Source: Developer.Mozilla.org: HTMLInputElement.setSelectionRange()
If you need just toUpperCase as formatting then you can use css instead. It seems the simplest solution is described here https://stackoverflow.com/a/3724990/12868043
That behaviour seems to be happening with .toUpperCase();
handleInputChangeUpperCase = e => {
this.setState({ [e.target.name]: e.target.value });
};
If you don't require the text to be upper case immediately on input, I would apply the method outside of the setState
This is supposed to be a reminder list with an input and output page. I currently have the information form the form saving in local storage but only displaying the most recent item added. How do I make it so everything from storage is displayed?
Ps I will make a button to delete the item later.
Input Page HTML
<form name="todoForm" action="" method="get">
Reminder : <input type="text" name="ReminderInput" id="ReminderInput"><br />
Date: <input type="datetime-local" name="DateInput" id="DateInput"><br />
Extra Information : <input type="text" name="InfoInput" id="InfoInput"><br />
<button onclick="storeValues(event)" type=submit>Submit</button>
</form>
Input page JS
function storeValues(e) {
e.preventDefault();
let storedReminders = JSON.parse(localStorage.getItem("Reminders")) || [];
const newReminderDetails = {
ReminderInput: document.getElementById('ReminderInput').value,
DateInput: document.getElementById('DateInput').value,
InfoInput: document.getElementById('InfoInput').value
}
storedReminders.push(newReminderDetails);
localStorage.setItem("Reminders", JSON.stringify(storedReminders));
console.log('storedReminders', storedReminders);
}
document.getElementById("todoForm").addEventListener("submit",storeValues );
Output page HTML
<h1>Reminders
</h1>
<h4 id='ReminderInput'> </h4>
<h4 id='DateInput'> </h4>
<h4 id='InfoInput'> </h4>
Output page JS
const renderReminder = (reminder) => {
document.getElementById('ReminderInput').textContent = reminder.ReminderInput;
document.getElementById('DateInput').textContent = reminder.DateInput;
document.getElementById('InfoInput').textContent = reminder.InfoInput;
};
renderReminder
const storedReminders = JSON.parse(localStorage.getItem("Reminders"));
if (!storedReminders) throw new Error('No Reminders');
const lastReminder = storedReminders.pop();
renderReminder(lastReminder);
Below is my code and I got a feeling I am really doing this wrong. I am new to react and I been spending many hours trying to figure this out with no luck.
I am trying to get users to input values of age, gender, height, weight etc..and then make the BMR box update with a value.
What i have so far is when the user clicks "Calculate for BMR" the onClick function spits out the correct result, but I have no clue how to get the value to appear in the "BMR input box" without any sort of refreshing.
Any help would be appreciated. Thanks
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleGenderChange = this.handleGenderChange.bind(this);
this.handleAgeChanged = this.handleAgeChanged.bind(this);
this.handleWeightChanged = this.handleWeightChanged.bind(this);
this.handleFeetChanged= this.handleFeetChanged.bind(this);
this.handleInchesChanged=this.handleInchesChanged.bind(this);
}
handleGenderChange = (event) => {
this.setState({Gender: event.target.value});
}
handleAgeChanged = (event) => {
this.setState({Age: event.target.value});
}
handleWeightChanged = (event) => {
this.setState({Weight: event.target.value});
}
handleHeightChanged = (event) => {
this.setState({Height: event.target.value});
}
handleFeetChanged = (event) => {
this.setState({Feet: event.target.value});
}
handleInchesChanged = (event) => {
this.setState({Inches: event.target.value});
}
onClick= (event) => {
event.preventDefault();
console.log(this.state);
const totalHeight = Number(this.state.Feet) * 12 + Number(this.state.Inches);
if(this.state.Gender == 'Male'){
var BMR = 66 + (6.23 * Number(this.state.Weight)) + (12.7 * totalHeight) - (6.8 * Number(this.state.Age));
console.log(BMR);
}
if(this.state.Gender == 'female'){
var BMR = 655 + (4.35 * Number(this.state.weight)) + (4.7 * totalHeight) - (4.7 * Number(this.state.age));
console.log(BMR);
}
}
render() {
return (
<div>
<Container>
<form>
<h3>Calories/TDEE Calculator</h3>
<div className="form-group">
<select className="form-control" value={this.state.Gender} onChange={this.handleGenderChange}>
<option disabled selected value> -- Gender-- </option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
<div className="form-group">
<label htmlFor="Age">Age</label>
<input className="form-control"
onChange={this.handleAgeChanged}
type="input"
id="Age"
name="Age"
placeholder="Enter an Age"
value={this.state.Age}
/>
</div>
<div className="form-group">
<label htmlFor="Weight">Weight (lbs)</label>
<input className="form-control"
onChange={this.handleWeightChanged}
type="input"
id="Weight"
name="Weight"
placeholder="Enter Weight"
value={this.state.Weight}
/>
</div>
<div className="form-group">
<label>"Height (Ft/In)"</label>
<input type="input"
name="Feet"
placeholder="Feet"
onChange={this.handleFeetChanged}
value={this.state.Feet}
/>
<input type="input"
name="Inches"
placeholder="Inches"
onChange={this.handleInchesChanged}
value={this.state.Inches}
/>
</div>
<div className="form-group">
<label>BMR</label>
<input className="form-control"
id="BMR"
name="BMR"
value= ""
/>
</div>
<button className="btn btn-lg btn-primary btn-block" onClick={this.onClick.bind(this)}>Click for BMR</button> <br />
</form>
</Container>
</div>
);
}
}
export default Calculator;
EDIT:
Thanks everyone for taking your time to help, it worked :D. I learned from all your replies.
You don't have anything that renders this.state.BMR so it's not too surprising you don't see it anywhere. Some advice: don't use nonbreaking spaces and <br>: that's what CSS is for. Also, don't use bind, use arrow notation to preserve this, there is no reason to use all these bind calls in your constructor.
And then for the actual question: you need to actually render something, so have an element that either shows the button, or shows the BMR value, based on whether you computed it:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
handleGenderChange(evt) {
// you really should validate this
this.setState({Gender: event.target.value});
}
...
render() {
return <div>
...
<inputelement onChange={evt => this.handleInchesChanged(evt) } />
...
{ this.showButtonOrResult() }
</div>;
}
showButtonOrResult() {
// if the button wasn't clicked yet, then `BMR` will not yet be a state value
if (!this.state.BMR) {
return <button className="..." onClick={evt => this.onClick(evt)>Click for BMR</button>
}
// if it IS a state value, just render it
return <div>Your BMR is: { this.state.BMR }</div>;
}
}
So when your button is clicked, you do what you do, calculate BMR, then setState that, and render() automatically gets called again. Now there is a value to show, and instead of the button, it'll show a div with the result.
Also note that we are absolutely not using bind(this) in the constructor, because that's ridiculous. Properly handle your events with an arrow function so that you get the event, and then pass the event to the correct function, with normal this context.
You need to label your state properties correctly. Your female calculation is going to spit out NaN because you're using {this.state.weight} when you're setting it as 'Weight'
Initialize your state
this.state = {
bmr: ''
};
Set the value of your input
<div className="form-group">
<label>BMR</label>
<input className="form-control"
id="BMR"
name="BMR"
value={this.state.bmr}
/>
</div>
Set the state in your onclick function
onClick = (event) => {
event.preventDefault();
let BMR;
const totalHeight = Number(this.state.Feet) * 12 + Number(this.state.Inches);
if (this.state.Gender === 'Male') {
BMR = 66 + (6.23 * Number(this.state.Weight)) + (12.7 * totalHeight) - (6.8 * Number(this.state.Age));
this.setState({ bmr: BMR });
} else if (this.state.Gender === 'Female') {
BMR = 655 + (4.35 * Number(this.state.Weight)) + (4.7 * totalHeight) - (4.7 * Number(this.state.Age));
this.setState({bmr: BMR});
}
}
my check boxes are not getting checked, when created dynamically. I am not able to find the problem. Though, when I hard-code the values for check box id and label for, it just works.
var category_list = this.props.categories_list.map(function(name, i) {
// debugger
return (
<div className="group-chkbx list-group-item">
<input key={i+11} type="checkbox" id={name.category_id} name="category" />
<label htmlFor={name.category_id}>{name.name}</label>
</div>
)
});
After a lot of research one of my colleague helped me out with a solution. The htmlFor and id must be same, but cannot be only numeric. The Ids that I'm using are purely numeric. When I added alphabet as a prefix, it just started working like charm. Thanks all for showing interest and helping out here.
There's nothing that would set the checked prop on them, anyway. When should they be checked?
(Also, remember that components in arrays (such as what .map returns) should have unique key props.)
If your checkboxes are not getting checked, most probably is that some other functionality is preventing it.
Here and example of how to get the checkbox values:
class WithChecks extends Component {
constructor(props){
super(props);
this.getValue = this.getValue.bind(this);
}
getValue(e){
const chk = e.target;
console.log(chk.checked);
console.log(chk.value);
}
render() {
const arr = ['a', 'b', 'c', 'd'];
return (
<div>
{
arr.map((value, index) => {
return (
<div key={index}>
<input type="checkbox"
id={'chk' + index}
onChange={this.getValue}
name="category"
value={value} />
<label htmlFor={'chk' + index}>{value}</label>
</div>
);
})
}
</div>
);
}
}
Maybe this can help to clarify.
The checked property of the input will control whether it is checked. Usually I use local state (or something from global redux state to control what is checked). Little Example:
class Something extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: 0
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
// Do Stuff
}
render() {
return (
<div>
{
this.props.categories_list.map(function(name, i) {
return (
<div className="group-chkbx list-group-item" key={i}>
<input checked={i === this.state.checked} onChange={this.handleChange} type="checkbox" id={name.category_id} name="category" />
<label htmlFor={name.category_id}>{name.name}</label>
</div>
)
});
}
</div>
);
}
}