React - Update Value Of Input After Submit - javascript

I'm trying to make a feature where a user can edit a submitted value. So to be completely clear:
You would enter some text
Click submit and that value will be pushed into an array
You will be able to see your value on the dom
If you made an error, you can click on that input and change the value, also updating the state of that value in the already pushed array.
On a button click, you will update the state and have a newly edited value.
I'm stuck on the part of changing the state of the value of the pushed items in the array.
For example:
If I were to click on the field of 'Bob', edit it and click submit, the value of whatever I changed it to would also change the state of what was originally in my array to the new value.
This is what I have so far:
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
notes: ['hello', 'bob'],
val: ''
}
}
submit = () => {
const { notes, val } = this.state
notes.push(val)
this.setState({notes})
}
handleEdit = e => {
console.log(e)
}
render() {
return (
<div>
<input
type="text"
onChange={e => this.setState({val: e.target.value})}
/>
<button onClick={this.submit}>Submit</button>
{this.state.notes.map(item => {
return (
<form onSubmit={e => e.preventDefault()}>
<input
type="text"
defaultValue={item}
onChange={e => this.setState({val: e.target.value})}
/>
<button onClick={() => this.handleEdit(item)}>Submit
Change</button>
</form>
)
})}
</div>
)
}
}

Try this kind of thing :
handleEdit = (item) => {
const notes = this.state.notes.slice();
const index = notes.indexOf(item);
notes[index] = this.state.val;
this.setState({
notes
})
}

Related

React Hooks: State is resetting to empty array even if I use the spread operator, prevState, etc

Simplified Code Sample right here
WORDS:
In short: My items state is resetting to [] with each NEW checkbox clicked and I dont understand why. But instead I want to use the spread operator and useState hooks to push an new item into the array so it's an array of objects.
Current behavior in detail: I'm creating an object and setting it in state using all (and I mean ALL) manner of React useState hooks like this: setItems((prevState) => [...prevState, { [evt.target.value]: evt.target.checked }]); As I check one item it's added and items becomes an array of objects (it being added over and over again is not the problem; I'll add a check for that later). BUT Here's the problem: when I click a NEW checkbox the items array is set back to [] and isnt concatenated with the prev items—even though I'm using prevState, spread operator, an arrow func as a wrapper, and all that jazz.
Desired behavior: Every time I check a checkbox, I want to update items [] to push a new object into it, which represents all items that have ever been checked. Before you say anything about duplicating: I'll add the check to see if an item is already in the array, and just update it if so. And before I add all items to cart, I'll strip all objects with checked = false states.
Can you help me understand what react lifecycle fundamentals I'm missing here; why is this happening? And how can I fix it?
CODE:
Where this is happening:
Simplified version of InputComponent
const InputComponent = ({ type, itemId, handleSearchQuery, onSubmit }) => {
const [items, setItems] = useState([]);
const captureInput = (evt) => {
if (evt.target.type === 'checkbox') {
setItems((prevState) => [...prevState, { [evt.target.value]: evt.target.checked }]);
}
};
const renderCheckbox = () => {
return (
<form>
<input type={type} name={itemId} value={itemId} onChange={setItem} />
<input name={itemId} type='submit' value='Add to Cart' />
</form>
);
};
return (
<div className='input-bar'>
{renderCheckbox()}
</div>
);
};
export default InputComponent;
Where this component is used:
import React from 'react';
import InputComponent from './InputComponent';
import './ResultsRenderer.css';
function ResultsRenderer({ data }) {
const renderListings = () => {
let listings = data ? data.Search : null;
return listings
? listings.map((item) => {
return (
<div className='cart-row'>
<InputComponent type='checkbox' className='cart-checkbox' itemId={item.imdbID} />
<div key={item.imdbID} className={item.imdbID}>
<img src={`${item.Poster}`} alt={item.Title} />
<div>
Title<em>{item.Title}</em>
</div>
<div>{item.Year}</div>
<em>{item.imdbID}</em>
</div>
</div>
);
})
: null;
};
return <>{renderListings()}</>;
}
export default ResultsRenderer;
items state is doing its job perfectly fine, you misunderstood the situation.
you're using items state inside InputComponent and for each listings item there is one InputComponent and each one have their own items, I think you meant to use items state inside ResultsRenderer Component to chase all selected items.
here is the changes you need to do:
const InputComponent = ({ type, itemId, setItems }) => {
const captureInput = (evt) => {
if (evt.target.type === "checkbox") {
setItems((prevState) => [
...prevState,
{ [evt.target.value]: evt.target.checked }
]);
}
};
return (
<div className="input-bar">
<form>
<input
type={type}
name={itemId}
value={itemId}
onChange={captureInput}
/>
<input name={itemId} type="submit" value="Add to Cart" />
</form>
</div>
);
};
export default InputComponent;
function ResultsRenderer() {
const [items, setItems] = useState([]);
useEffect(() => {
console.log(items);
}, [items]);
const renderListings = () => {
let listings = [
{ itemId: 1, title: "Hello" },
{ itemId: 2, title: "World" }
];
return listings
? listings.map((item) => {
return (
<div className="cart-row">
<InputComponent
type="checkbox"
className="cart-checkbox"
itemId={item.itemId}
setItems={setItems}
/>
<div key={item.itemId} className={item.itemId}>
<div>
Title<em>{item.Title}</em>
</div>
</div>
</div>
);
})
: null;
};
return <>{renderListings()}</>;
}
and here is the working demo: https://codesandbox.io/s/boring-cookies-t0g4e?file=/src/InputComponent.jsx

when I click add button multiple times it should show I am here div with delete button with multiple times

I am trying to build a simple ui so that I can learn react.
right now when I click an add button it will show I am here div and delete button
when I click add button multiple times it should show I am here div with delete button with multiple times.
so I research and found this example https://www.skptricks.com/2018/06/append-or-prepend-html-using-reactjs.html
using this example I implemented the appendData method but still its not adding the div multiple times.
in my console I am able to see how many times divs are added console.log("this.displayData---->", this.displayData);
can you tell me how to fix it.
so that in future I will fix it myself
https://stackblitz.com/edit/react-b2d3rb?file=demo.js
onClick = () => {
this.setState({ showResults: true });
this.setState({ showOrHideSearch: true });
this.displayData.push(
<div style={{ display: this.state.showOrHideSearch ? "" : "none" }}>
{" "}
I am here
<input
ref="rbc-toolbar-label"
type="submit"
value="Delete"
onClick={this.onDelete}
/>
</div>
);
console.log("this.displayData---->", this.displayData);
this.setState({ showdata: this.displayData });
};
First thing is you should not use this.setState multiple times, instead you should do them in one line. And instead of pushing data into class variables, you should set that data into your state variable and the same variable you should use in your render function. It will be good if you can share your complete code..
import React, { Component } from 'react';
import Calendar from 'rc-calendar';
import DatePicker from 'rc-calendar/lib/Picker';
import 'rc-calendar/assets/index.css';
import moment from 'moment';
class CalendarPage extends Component {
constructor(props) {
super(props);
console.log("AsyncValidationForm this.props---->", this.props);
this.state = {
displayData: []
};
}
onClick = () => {
let displayData = [...this.state.displayData];
displayData.push( { text: 'I am here' });
this.setState({ displayData: displayData });
};
onDelete = index => {
let displayData = [...this.state.displayData];
if(index > -1){
displayData.splice(index, 1);
}
this.setState({ displayData: displayData });
};
handleChange = name => event => {
const value = event.target.value;
this.setState(
{
[name]: value,
pristine: false
},
() => {
this.props.handleChange(name, value); //setState username, password of VerticalLinearStepper.js
}
);
};
onSubmit(event) {
event.preventDefault();
var newItemValue = this.refs.itemName.value;
if(newItemValue) {
this.props.addItem({newItemValue});
this.refs.form.reset();
}
}
render() {
const { handleSubmit, pristine, reset, submitting } = this.props;
let { displayData} = this.state;
return (
<form onSubmit={handleSubmit}>
<div>
<input type="submit" value="add" onClick={this.onClick} />
{displayData.length > 0 ? displayData.map(function(data, index) {
return (
<div key={index}>
{data.text} - For testing added index on screen {index}
<input
ref="rbc-toolbar-label"
type="submit"
value="Delete"
onClick={() => this.onDelete(index)}
/>
</div>
)}, this) : null}
</div>
</form>
);
}
}
export default CalendarPage;

How can i clear my input when i'm submit my event (reactJs app)

I have 3 inputs whose value I save and click on my btn, I would like to clear these inputs.......
my function that saves the value of one of my inputs:
onChangeIdentity = (event) => {
this.newPlayer = Object.assign({}, this.newPlayer, { strPlayer:
event.target.value})
}
my input:
<Input style={{width:'30%'}} onChange={ this.onChangeIdentity }
ref='myFormRef' value={ this.newPlayer.strPlayer } type='text'
placeholder='Nom & Prenom'/>
and the function that must clear my input:
addPlayer = () => {
console.log('my new Player: ' , this.newPlayer);
this.setState({
teamPlayers: [...this.state.teamPlayers, this.newPlayer]
})
this.refs.myFormRef.value = ""
}
I tried several ways to declare my refs but nothing works.....
any ideas?
You input's values are driven by the state of the component value={this.newPlayer.strPlayer}. If you want to clear the input's value you need to clear the state which maps to it, for example:
this.setState({newPlayer: {strPlayer: ''}});
After setting the state, the component updates automatically and renders the input as empty.
Here is a full example component:
class MyComponent extends Component {
state = {
inputValue: ""
};
render() {
return (
<div>
<input
type="text"
value={this.state.inputValue}
onChange={event => this.setState({ inputValue: event.target.value })}
/>
<button
onClick={() => {
/* submit this.state.inputValue */
this.setState({ inputValue: "" }); // reset input value
}}
>
submit
</button>
</div>
);
}
}

How to add values of dyanamically added fields

I've tried to add new fields here, each time button '+' is clicked it adds field input. It is working fine but the problem I've stuck upon is I want to add the value of those input fields. As I am new to react I am not finding a way to achieve it. Is it possible to achieve this.
class InputFields extends React.Component{
render(){
return (
<div>
<input name={`value[${this.props.index + 1}]`} onChange={this.onChangeValue} />
</div>
);
}
}
class Main extends React.Component{
constructor(props){
super(props);
this.values = props.value;
this.state={
inputs:[],
values:[]
};
this.addInputs = this.addInputs.bind(this);
}
addInputs() {
const inputs = this.state.inputs.concat(InputFields);
this.setState({ inputs });
}
onChangeValue(e){
var value = e.target.value;
this.value =value;
this.addValues();
}
addValues(){
...
}
render () {
const inputs = this.state.inputs.map((Element, index) => {
return <Element key={ index } index={ index } />
});
return <div>
<div>
<input name={`value[${this.props.index}]`} onChange={this.onChangeValue} />
</div>
<div>
<button className="btn btn-sm btn-primary" onClick={this.addInputs}>+</button>
</div>
</div>
}
}
ReactDOM.render(
<Main />,
document.getElementById('calculator')
);
It't not required to manage two different variables to manage it, you can loop it through the array and can change the value on onChange event
import React from "react";
export default class Example extends React.Component {
state = {
values: [null]
};
add() {
this.setState(prevState => prevState.values.push(null));
}
changeVal(val, index) {
this.setState(prevState => (prevState.values[index] = parseFloat(val)));
}
getSum() {
let sum = 0;
for (let i = 0; i < this.state.values.length; i++) {
if (this.state.values[i] !== null) {
sum += this.state.values[i];
}
}
return sum;
}
render() {
return (
<div>
{this.state.values.map((val, index) => (
<div key={index}>
<input
onChange={e => this.changeVal(e.target.value, index)}
type="number"
value={val}
placeholder="Enter a value"
/>
</div>
))}
<hr />
Sum is {this.getSum()}
<hr />
<button onClick={this.add.bind(this)}> +Add</button>
</div>
);
}
}
Edit
Added the method getSum() and converting the number to float in changeVal() method
Codesandbox link - https://codesandbox.io/s/235o6xoxyr
In react, the view is a function of data: UI = fn(data)
This means that you'll write a component tree that can transform data to view.
And only manipulate data, unlike what you might be familiar with in jQuery for example.
In practice, this would mean:
let a component Input handle the rendering of one input:
const Input = ({value, onChange}) =>
<input value={value} onChange={event => event.target.value} />
in your state, only save the list of input values as strings. React will take care of transforming each value to an Input component later on
this.state = {inputs: []}
write a function responsible of adding new inputs, to the state and not the view
addInput = () => {
this.setState({
inputs: this.state.inputs.concat('')
})
}
create a method that takes care of changing the value of one input in the list
changeValue = (i, newValue) => {
this.setState({
inputs: [
...this.state.inputs.slice(0, i),
newValue,
...this.state.inputs.slice(i+1)]
})
}
in the render method of Main, loop over your list of inputs and transform to a list of Input components
this.state.inputs.map(
(input, i) =>
<Input
key={i}
value={input}
onChange={newValue => this.changeValue(i, newValue)}
/>
)

Error dynamically updating an array list in ReactJs

I am learning reactJS and so I am trying my hands on an example. This example has a form textfield that can add an item to an existing array on click of a button. I am having errors here as when I enter a text and click on the button, the array list is not updated except I try to make changes to the text entered in the textfield. This is what I am doing:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
currentName : '',
arrays : ['john', 'james', 'timothy']
}
}
render() {
const showNames = this.state.arrays.map((thisName) => {
const values = <li>{thisName}</li>;
return values;
});
const getText = (e) => {
let value = e.target.value;
this.setState({
currentName : value
})
}
const addToUsers = () => {
this.state.arrays.push(this.state.currentName)
}
return (
<div>
<p>Add new name to List</p><br/>
<form>
<input type="text" onChange={getText}/>
<button type="button" onClick={addToUsers}>Add User</button>
</form>
<ul>
{showNames}
</ul>
</div>
);
}
}
export default App;
There are a host of things wrong with this, but your issue is likely that you need to use setState to modify state.
import React, { Component } from 'react';
class App extends Component {
constructor(){
super();
this.state = {
names: ['john', 'james', 'timothy']
}
}
addToUsers = () => {
this.setState(
prevState => ({
names: [...prevState.names, this.input.value]
})
)
}
render() {
const names = this.state.names.map(
(name, index) => <li key={index}>{name}</li>
)
return (
<div>
<p>Add new name to List</p><br/>
<form>
<input type="text" ref={e => this.input = e} />
<button type="button" onClick={this.addToUsers}>Add User</button>
</form>
<ul>
{names}
</ul>
</div>
)
}
}
export default App;
This quick edit changes a few things:
Uses setState for the addToUsers method
Eliminate onChange tracking and pull the name directly from the input when the button is clicked
Move the addToUsers method out to the component class rather than defining it on render
Rename this.state.arrays to this.state.names
Simplify conversion of this.state.names into list items
Set key on array elements (name list items)
Use prevState in setState to avoid race conditions
You need to make sure you update state using the setState method.
When you update arrays you are reaching into the state object and manipulating the data directly instead of using the method.
Instead try something like:
const addToUsers = () => {
const newArray = this.state.arrays.concat([this.state.currentName]);
this.setState({
arrays: newArray
});
}
You probably must add
onChange={getText}.bind(this)
to your functions.
Also change this
const addToUsers = () => {
this.state.arrays.push(this.state.currentName)
}
to this
const addToUsers = () => {
this.setState({here put your variable})
}

Categories

Resources