React, not able to change/editing anything in textbox? - javascript

I have data that I am getting from api. I am filling the data in the array. I am able to display the data properly. I am not able to make any change in the DisplayOrder Textboxes. Please find my data and code. What to do so that textbox is editable?
[{"featureID ":"10,"descrText":"Test1","featureText":"<h1>Feature1</h1>","displayOrder":"1},
{"featureID ":"11,"descrText":"Test2","featureText":"<h1>Feature2</h1>","displayOrder":"2},
{"featureID ":"12,"descrText":"Test3","featureText":"<h1>Feature3</h1>","displayOrder":"3}]
import React from "react";
import ReactHtmlParser from 'react-html-parser';
export class EditFeatures extends React.Component {
constructor(props) {
super(props);
this.state = {
FeatureID: "",
DisplayOrder: "",
DescrText: "",
FeatureText: "",
Feature:[],
};
}
componentDidMount() {
this.DisplayFeatures();
}
DisplayFeatures() {
fetch(REQUEST_URL, { "Content-Type": "application/xml; charset=utf-8" })
.then(response => response.json())
.then((data) => {
this.setState({
Feature:data,
loading: false
})
})
}
render() {
return (
<div>
<form>
<table width="100%" cellpadding="0" cellpadding="0" border="1"><tbody>
{this.state.Feature.map((item, index) => {
return [
<tr key={item.FeatureID}>
<td width="50px">{item.featureID}
<input type="text" name=="DisplayOrder" size="5" maxLength="10" value={item.displayOrder}
onChange={(ev) => this.setState({ DisplayOrder: ev.target.value })} /></td>
<td align="left"><font size="3">{ReactHtmlParser(item.descrText)}</font></td>
<td align="left">{ReactHtmlParser(item.featureText)}</td></tr>
];})}
</tbody></table>
<button type="submit" name="submit">Update</button>
</form>
</div>
);
}
}
export default EditFeatures;

So when you're rendering out the value of display order, you're using the item.displayOrder as the inputs value; but in your onChange event, you're updating this.state.DisplayOrder. For you to be able to update the value, you would need to update item.displayOrder value, not the states; which would be something like
this.setState(prevState => ({
Feature: prevState.Feature.map(feature => {
if (feature.featureID === IdOfFeatureYouWantToUpdate) {
return { ...feature, { displayOrder: newValue }};
}
})
}));
If you're wanting to use the states DisplayOrder, then for the value of the input you need to use this.state.DisplayOrder instead of item.displayOrder.

You are not updating the same state, This might help
<input type="text" id={item.FeatureID} name="DisplayOrder" size="5" maxLength="10" value={item.displayOrder}
onChange={
(ev) =>{
const newFeature = this.state.Feature.map(f => {
if (f.FeatureID == ev.target.id) {
f.displayOrder = ev.target.value;
}
return f;
});
this.setState({ Feature: newFeature })
}
} />

Related

How to set multiple object value with special key on react js

i need your help to set the new value in multiple object. I had object like this:
constructor(props){
this.state = {
objData : [{
score:{q1:null,q2:null,q3:null},
data:{id:123, name:"Steven CHS"}
},
{
score:{q1:null,q2:null,q3:null},
data:{id:124, name:"Christian"}
},
]
}
}
and i would like to change the value by key q1,q2, anda q3. When i tried to use destructor like this, it's not working.
const handleChangeScore = (e,type,id) =>{
const cScore = e.target.value;
this.setState((state) => {
return {
objData: state.objData.map((item) => {
if(item.data.id !== e.target.name) return item;
else return {...item.score.q1, cScore};
})
};
});
}
this is the JSX where handleChangeScore() is used:
this.state.objData .map((v,index)=>(
<tr>
<td>{index+1}</td>
<td>{v.data.id} - {v.data.name}</td>
<td><input type="text" name={v.data.id} className="form-control" onChange={(e)=>handleChangeScore(e,"q1",v.data.id)} defaultValue={(v.score.q1) ? v.score.q1 : 0} /></td>
<td><input type="text" name={v.data.id} className="form-control" onChange={(e)=>handleChangeScore(e,"q2",v.data.id)} defaultValue={(v.score.q2) ? v.score.q2: 0} /></td>
</tr>
))
The problem is when i use destructor to change the value on multiple object with specific key its not work or not change the value. Can anyone help me to fix my code ? Here's the full code in codesanbox
Few things to be fixed
Your item.data.id is number and e.target.name is string. To compare them without type comparison use != instead of !==.
The else block should be corrected as below.
handleChangeScore = (e, type, id) => {
const cScore = e.target.value;
this.setState((state) => {
return {
...state,
objData: state.objData.map((item) => {
if (item.data.id != e.target.name) return item;
else {
return { ...item, score: { ...item.score, [type]: cScore } };
}
})
};
});
};
Code Sandbox
Try below code no need to use map(). just pass the index in this.handleChangeScore() function !
And put handleChangeScore() this function in outside of render() !
export class App extends Component {
constructor(props) {
super(props);
this.state = {
objData: [
{
score: { q1: null, q2: null, q3: null },
data: { id: 123, name: "Steven CHS" }
},
{
score: { q1: null, q2: null, q3: null },
data: { id: 124, name: "Christian" }
}
]
};
}
handleChangeScore = (value, index, childObj) => {
this.state.objData[index].score[childObj] = value;
this.setState(this.state);
};
render() {
return (
<div className="App">
<table border="1">
{this.state.objData.map((v, index) => (
<tr>
<td>{index + 1}</td>
<td>
{v.data.id} - {v.data.name}
</td>
<td>
<input
type="text"
name={v.data.id}
className="form-control"
onChange={(e) => this.handleChangeScore(e.target.value, index, "q1")}
defaultValue={v.score.q1 ? v.score.q1 : 0}
/>
</td>
<td>
<input
type="text"
name={v.data.id}
className="form-control"
onChange={(e) => this.handleChangeScore(e.target.value, index, "q2")}
defaultValue={v.score.q2 ? v.score.q2 : 0}
/>
</td>
</tr>
))}
</table>
</div>
);
}
}
export default App;

Get figure from function and set it as state once user types in input

I have a component that I want to use to update a 'balance' in a database.
To do this, I am pulling the figure in my componentDidMount using axios.get:
componentDidMount() {
axios.get("/api/fetch/fetchEditDebt", {
params: {
id: this.props.match.params.id
}
})
.then((response) => {
this.setState({
balance: response.data.balance,
})
})
}
I then have an input which takes the amount the user wants to add to the balance:
<form method="POST" onSubmit={this.onSubmit}>
<input className="edit-balance-input" type="number" name="add" value={this.state.add} onChange={this.onChange} step="1" />
<button className="edit-balance-button" type="submit">Save</button>
</form>
I then use a function to take the original balance from state, and the 'add' figure from the input state, and add them together:
const calculateUpdatedBalance = () => {
return parseInt(this.state.balance) + parseInt(this.state.add)
}
And this updated figure is then rendered inside of a span so the user can see the new balance:
<div className="edit-balance-balance-container">
<p className="edit-balance-balance-paragraph">Updated balance: </p>
<span className="edit-balance-updated">-£{calculateUpdatedBalance()}</span>
</div>
This all works great, and as expected - the difficulty comes in when I then want to post the updated balance to my database. I tried to post the add state, but unsurprisingly that just updates the balance to the amount the user put into the input.
So how do I access the figure generated by my calculateUpdatedBalance() function? I thought about trying to setState() in the function, but that produces a "too many state updates" error.
Does anyone have any suggestions for how I can get that updated figure, and post that to my database?
Here's my full component for reference:
class Add extends Component {
constructor(props) {
super(props)
this.state = {
balance: '',
add: 0,
updatedBalance: '',
fetchInProgress: false
}
this.onChange = this.onChange.bind(this);
}
componentDidMount() {
this.setState({
fetchInProgress: true
})
axios.get("/api/fetch/fetchEditDebt", {
params: {
id: this.props.match.params.id
}
})
.then((response) => {
this.setState({
balance: response.data.balance,
fetchInProgress: false
})
})
.catch((error) => {
this.setState({
fetchInProgress: false
})
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
})
}
onChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
console.log(this.state.add)
}
onSubmit = async(e) => {
e.preventDefault();
console.log(this.props.match.params.id)
await axios.post("/api/edit/editDebtBalance", {
balance: this.state.add,
}, {
params: {
id: this.props.match.params.id
}
})
this.props.history.push('/dashboard');
}
render() {
const calculateUpdatedBalance = () => {
return parseInt(this.state.balance) + parseInt(this.state.add)
}
return (
<section className="edit-balance-section">
<div className="edit-balance-container">
<DashboardReturn />
<div className="edit-balance-content">
<p className="edit-balance-paragraph">How much would you like to add to your balance?</p>
<div className="edit-balance-balance-container">
<p className="edit-balance-balance-paragraph">Current Balance: </p>
<span className="edit-balance-original">-£{this.state.balance}</span>
</div>
<div className="edit-balance-balance-container">
<p className="edit-balance-balance-paragraph">Updated balance: </p>
<span className="edit-balance-updated">-£{calculateUpdatedBalance()}</span>
</div>
<form method="POST" onSubmit={this.onSubmit}>
<input className="edit-balance-input" type="number" name="add" value={this.state.add} onChange={this.onChange} step="1" />
<button className="edit-balance-button" type="submit">Save</button>
</form>
</div>
</div>
</section>
)
}
}
If you make calculateUpdatedBalance() a member method of the Add component, then you can call it from both render() and onSubmit():
calculateUpdatedBalance() {
return parseInt(this.state.balance) + parseInt(this.state.add)
}
onSubmit = async (e) => {
...
await axios.post("/api/edit/editDebtBalance", {
balance: this.calculateUpdatedBalance(),
...
};
render() {
return (
...
<span className="edit-balance-updated">-£{this.calculateUpdatedBalance()}</span>
...
}

React. Transferring data from textarea to array JSON

I just started working with React and JSON and require some help. There is a textarea field in which a user enters some data. How to read row-wise the entered text as an array into a JSON variable of the request? Any assistance would be greatly appreciated.
The result I want is
{
id: 3,
name: 'Monika',
birthDay: '1999/01/01',
countryDTO: 'USA',
films: [
'Leon:The Professional',
'Star wars',
'Django Unchained',
],
} ```
My code:
import React from 'react';
import { Form, FormGroup, Label } from 'reactstrap';
import '../app.css';
export class EditActor extends React.Component {
state = {
id: '',
name: '',
birthDay: '',
countryDTO: '',
films: [],
}
componentDidMount() {
if (this.props.actor) {
const { name, birthDay, countryDTO, films } = this.props.actor
this.setState({ name, birthDay, countryDTO, films });
}
}
submitNew = e => {
alert("Actor added"),
e.preventDefault();
fetch('api/Actors', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: this.state.name,
birthDay: this.state.birthDay,
countryDTO: {
title: this.state.countryDTO
},
films: [{ title: this.state.films }]
})
})
.then(() => {
this.props.toggle();
})
.catch(err => console.log(err));
this.setState({
id: '',
name: '',
birthDay: '',
countryDTO: '',
films: ''
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value })
}
render() {
return <div>
<table>
<tr>
<td colspan="2">
<h3> <b>Add actor</b></h3>
<FormGroup>
<Label for="id">Id: </Label>
<input type="text" name="id" onChange={this.onChange} value={this.state.id} /><p />
<Label for="name">Name:</Label>
<input type="text" name="name" onChange={this.onChange} value={this.state.name} /><p />
<Label for="birthDay">Birth day:</Label>
<input type="text" name="birthDay" onChange={this.onChange} value={this.state.birthDay} placeholder="1990/12/31" /><p />
<Label for="country">Country:</Label>
<input type="text" name="countryDTO" onChange={this.onChange} value={this.state.countryDTO} /><p />
<Label for="Films">Films:</Label>
<textarea name="films" value={this.state.films} onChange={this.onChange} /><p />
</FormGroup>
</td>
</tr>
<tr>
<td>
<Form onSubmit={this.submitNew}>
<button class="editButtn">Enter</button>
</Form>
</td>
</tr>
</table >
</div>;
}
}
export default EditActor;
If you change the below code it will work automatically.
State declaration
this.state = {
name: 'React',
films:["Palash","Kanti"]
};
Change in onechange function
onChange = e => {
console.log("values: ", e.target.value)
this.setState({ [e.target.name]: e.target.value.split(",") })
}
change in textarea
<textarea name="films" value={this.state.films.map(r=>r).join(",")} onChange={this.onChange} />
Code is here:
https://stackblitz.com/edit/react-3hrkme
You have to close textarea tag and the following code is :
<textarea name="films" value={this.state.films} onChange={this.onChange} >{this.state.films}</textarea>
My understanding of your problem is that you would like to have each line in the text area dynamically added as an entry in the films array. This can be achieved as follows:
import React, { Component } from "react";
export default class textAreaRowsInState extends Component {
constructor(props) {
super(props);
this.state = {
currentTextareaValue: "",
films: []
};
}
handleChange = e => {
const { films } = this.state;
const text = e.target.value;
if (e.key === "Enter") {
// Get last line of textarea and push into films array
const lastEl = text.split("\n").slice(-1)[0];
films.push(lastEl);
this.setState({ films });
} else {
this.setState({ currentTextareaValue: text });
}
};
render() {
const { currentTextareaValue } = this.state;
return (
<textarea
defaultValue={currentTextareaValue}
onKeyPress={this.handleChange}
/>
);
}
}
Keep in mind that this method is not perfect. For example, it will fail if you add a new line anywhere other than at the end of the textarea. You can view this solution in action here:
https://codesandbox.io/s/infallible-cdn-135du?fontsize=14&hidenavigation=1&theme=dark
change textarea() tag
to
<textarea name="films" value={this.state.films} onChange={this.onChange} >{this.state.films}</textarea>
You can use split() :
films: {this.state.films.split(",")}

Select all checkbox of table on click of the another table checkbox using react

I have checkboxes for each td in a table. Now, I have another table which has one checkbox. On checking this, I want to select all other checkboxes of first table.
Here is the code,
<tr key={key}>
<td align="center"> <input type="checkbox" name="myTextEditBox" value="checked" /></td>
<td>{item.technology}</td>
</tr>
for second table I did,
handleCheckBox = () => {
console.log("callling the handle change");
this.setState({
isCheckd: !this.state.isCheckd
})
}
constructure(props) {
this.state = { isCheckd: false }
<td className="text-right mr-1"><input type="checkbox" checked={this.state.isCheckd} onChange={this.handleCheckBox} /></td>
}
Now, In this click handler works. But, now how do I select all other checkboxes of another table, without using jquery.
Can any one help me with this ?
Tried solution -
state = { dynamicProp: {}, isCheckd: false,}
handleCheckBox = () => {
this.setState({
isCheckd: !this.state.isCheckd
}, () => {
this.props.jobs.forEach((item) =>
this.setState(prevState => ({
dynamicProp: {
...prevState.dynamicProp,
[item.jdName]: prevState.isCheckd
}
})
))
});
}
handleTableCheckboxChange = (e) => {
const target = e.target.name;
const checked = e.target.checked;
this.setState(prevState => ({
dynamicProp: {
...prevState.dynamicProp,
[target]: checked
}
}), () => {
const result = this.allTrue(this.state.dynamicProp);
this.setState({
isCheckd: result ? false : true
})
})
}
allTrue(obj) {
for (var o in obj)
if (!obj[o]) return true;
return false;
}
and then passing all the props to the child element. Now, the problem I am facing now is in the handleTableCheckboxChange method where I am not getting the way you used filter to get the unchecked element. and then the select all check will get changed.
I did not understand your code well so I understand it from what you have written. And then I have created a working example for you. Hope it can help you!
UPDATED CODE
const Table=(props)=>(
<table>
{
props.items.map((item, i) => (
<tr key={i}>
<td>
<input type="checkbox" checked={props.parentState[item.name]} name={item.name} onChange={props.handleChange} />
</td>
<td>{item.value}</td>
</tr>
))
}
</table>
);
class App extends React.Component {
items = [
{
value: 'EN',
name: 'field1'
},
{
value: 'IT',
name: 'field2',
}
];
state = {
checkAll: false,
};
render() {
return (
<div>
Check All
<input type="checkbox" onChange={this.handleCheckAll} checked={this.state.checkAll}/>
<Table
handleChange={this.handleChange}
items={this.items}
parentState={this.state}
/>
</div>
);
}
handleCheckAll = () => {
this.setState({
checkAll: !this.state.checkAll
}, () => {
this.items.forEach((item) => this.setState({ [item.name]: this.state.checkAll}))
});
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.checked
}, () => {
const uncheckedItems = this.items.filter((item) => !this.state[item.name])
this.setState({
checkAll: uncheckedItems.length === 0?true:false
});
});
}
}
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>
Here's a sample code. Obviously i haven't covered all the fail cases. Still you will get an idea about how that can be done.
import React from 'react';
export default class CheckboxIndex extends React.Component{
constructor(props){
super(props);
this.state = {
isChecked : false,
allTDS : [
{name:"name 1",value:false},
{name:"name 2",value:false},
{name:"name 3",value:false},
{name:"name 4",value:false},
{name:"name 5",value:false},
{name:"name 6",value:false},
{name:"name 7",value:false}
]
}
}
handleCheckBox = () => {
this.setState({isChecked: !this.state.isChecked});
let tempTDS = this.state.allTDS;
for (let i =0; i < tempTDS.length; i++){
tempTDS[i].value = !this.state.isChecked;
}
this.setState({allTDS : tempTDS});
};
render(){
let listOfTR;
if(this.state.allTDS.length){
listOfTR = this.state.allTDS.map((item,index)=>{
return(
<tr key={item.name}>
<td>
<label htmlFor={item.name}>
<input id={item.name} checked={item.value} type="checkbox"
onChange={()=>{
let tempObj = this.state.allTDS;
tempObj[index].value = !tempObj[index].value;
this.setState({allTDS:tempObj});
}}/>{item.name}
</label>
</td>
</tr>
)
})
}
return(
<div>
<label htmlFor="allTDS">
<input type="checkbox" id="allTDS" name="all" checked={this.state.isChecked}
onChange={this.handleCheckBox}/> All
</label>
<table>
<tbody>
{listOfTR}
</tbody>
</table>
</div>
)
}
}
class CheckboxTest extends React.Component {
constructor() {
super();
this.state = {
selectAll: false,
data1: false,
data2: false
};
this.selectAll = this.selectAll.bind(this);
this.selectField = this.selectField.bind(this);
}
selectAll() {
this.setState({
data1: !this.state.selectAll,
data2: !this.state.selectAll,
selectAll: !this.state.selectAll
});
}
selectField(event) {
if (event.target.value === "data1")
this.setState({ data1: !this.state.data1 });
else this.setState({ data2: !this.state.data2 });
}
render() {
return (
<div className="App">
<table>
<tbody>
<tr>
<td align="center">
<input
checked={this.state.data1}
onChange={this.selectField}
type="checkbox"
name="myTextEditBox1"
value="data1"
/>
</td>
<td>data 1</td>
</tr>
<tr>
<td align="center">
<input
checked={this.state.data2}
onChange={this.selectField}
type="checkbox"
name="myTextEditBox2"
value="data2"
/>
</td>
<td>data 2</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td align="center">
<input
onChange={this.selectAll}
type="checkbox"
name="myTextEditBox1"
value="all"
/>
</td>
<td>Click all</td>
</tr>
</tbody>
</table>
</div>
);
}
}
You can use the state for implementing this. Maintain state for each checkbox field and when the checkbox is changed trigger a method to set the state according to your conditions
this.setState({
isCheckd: !this.state.isCheckd
})
In this case, the isCheckd value in state corresponds to one checkbox. To select all other checkboxes of another table you have to update the values set in setState to all the values that correspond to all the boxes you want checked.
So if you have another 3 checkboxes who's values correspond to isCheckd1, isCheckd2, and isCheckd3 in state then your handler would be:
this.setState({
isCheckd1: true,
isCheckd2: true,
isCheckd3: true
})
Try this approach. you can select both the individual and check all checkbox.
class App extends React.Component {
items = ['EN', 'IT', 'FR', 'GR', 'RU'];
state = {
checkAll: false,
items : [
{'label': 'EN', 'checked': false},
{'label': 'IN', 'checked': false},
{'label': 'FR', 'checked': false},
]
};
render() {
return (
<div>
Check All
<input type="checkbox" onChange={this.handleCheckAll} />
<table>
{
this.state.items.map((item, i) => (
<tr key={i}>
<td>
<input type="checkbox" checked={item.checked} />
</td>
<td>{item.label}</td>
</tr>
))
}
</table>
</div>
);
}
handleCheckAll = () => {
let checkAll = !this.state.checkAll;
let items = this.state.items;
items.map((item, i) => {
item.checked = checkAll;
});
this.setState({
checkAll,
items
});
}
}

How to fill dropdown with JSON data in React?

I try to fill in a dropdown with data from the JSON format but for now the dropdown is empty (no results found...)
I certainly have a mistake and I can not understand where I'm confusing.
I will attach a screen of my API.
I want to get Station and NameStation..
API for Stations
My code:
import React, { Component } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
function parseStations(stations){
return stations.map((station) => {
return { label: station.NameStation, value: station.Station };
});
}
export default class Weather extends Component {
constructor(props) {
super(props);
this.state = {
options: [
{ value: true, label: 'Yes' },
{ value: false, label: 'No' }
], stations: [
],
value: null
}
this.onChange = this.onChange.bind(this);
}
onChange(event) {
this.setState({ value: event.value });
console.log('Boolean Select value changed to', event.value);
}
componentDidMount() {
this.getStations();
}
getStations() {
fetch('http://localhost:56348/api/stations', {
data: 'Station',
data: 'NameStation',
method: "GET"
}).then(res => res.json())
.then(res => this.setState({ stations: parseStations(res.stations) }))
//.then(res => this.setState({ stations: res.stations }))
//.catch(e => )
}
render() {
return (
<div className="MasterSection">
<div className="wrapper">
<div className="section">Изберете № на станция</div>
<Select
onChange={this.onChange}
//options={this.state.options}
options={this.state.stations}
value={this.state.value}
clearable={false}
/>
</div>
<div class="section">
<input type="text" class="form-control" placeholder="Брой дни назад" aria-label="Username" aria-describedby="basic-addon1"></input>
</div>
<div class="section">
<button type="button" class="btn btn-outline-dark">Покажи</button>
</div>
</div>
);
}
}
Seems you made a typo naming the prop stations instead of options :
<Select
onChange={this.onChange}
options={this.state.stations} // here
value={this.state.value}
clearable={false}
/>
Edit : you'll need to parse your json first to pass a proper array of objects like this : [{ label: nameStation, value: Station }]
Edit 2 : Here's a parser for your data :
function parseStations(stations){
return stations.map((station) => {
return { label: station.NameStation, value: station.Station };
});
}
You can call this in your async request before setting the state :
.then(res => this.setState({ stations: parseStations(res.stations) }))
componentDidMount() is executed only after render() is completed. so there's no way getStations() gets executed at the time your UI gets rendered. it is not a good idea to setState inside componentDidMount() as it triggers re rendering. use componentWillMount() instead.
correct the typo that Dyo mentioned and use options={this.state.stations}

Categories