How to call specific Object from ObjectArray - reactjs

Trying to get e.target.data from the objects generated. console.log displays they have props with the data value I assigned them with. How are event specific objects called? I need to access the original value and also want to onClick delete them. But so far everything i tried, only returns _this2 TypeError (is not a function), or data i tried to pass with the onClick handler wasn't passed. this.props.plz_zwischenis a simple array of strings and passed from parent Component.
import React, { Component } from 'react';
export default class checkBox extends Component {
constructor(){
super();
this.state = {
checkboxState: false
};
this.toggle = this.toggle.bind(this);
}
toggle(e){
console.log('toggle was triggered');
}
render(){
let miniBox = this.props.plz_zwischen.map(function(a, index){
return <li key={index} data={a}> <label> {a} </label> <input type="checkbox" onClick={(e) => this.toggle()} /></li>;
});
return(
<div>
<ul id="rowlist">
{miniBox}
</ul>
</div>
);
}
}

When you need to access the another prop in map, it is always a good idea to abstract it to a separate component
function ListItem(props) {
return (
<li>
<label> {props.data} </label>
<input type="checkbox" onClick={(e) => props.toggle(props.data)} />
</li>
);
}
class CheckBox extends React.Component {
constructor(props){
super(props);
this.state = {
checkboxState: false
};
this.toggle = this.toggle.bind(this);
}
toggle(a){
console.log(a);
}
render(){
let miniBox = this.props.plz_zwischen.map((a, index)=>{
return <ListItem key={index} data={a} toggle={this.toggle} />;
});
return(
<div>
<ul id="rowlist">
{miniBox}
</ul>
</div>
);
}
}
ReactDOM.render(<CheckBox plz_zwischen={['a','b','c']}/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app" />
That way you can access the single prop in the child component.
Another way to perform the same thing would be to attach it to the DOM as a custom attribute (since it is a string).
<li data-item={a} key={index} data={a}> <label> {a} </label> <input type="checkbox" onClick={(e) => this.toggle()} /></li>
and then in on click:
event.target.getAttribute('data-item')
Do note that components must begin with capital letters

Related

stuck at Displaying Updated Array Data

I have an array List and I'm using the .push() method to add new elements to it and then concat the input with List in Onclickadd method but its not updating the array to display the items in to-do
import React from 'react'
import './App.css'
class App extends React.Component {
constructor(){
super()
this.state={
List: ['potato']
}
}
onAddChange=(event)=>{
this.setState=({
input: event.target.value
})
}
Onclickadd=()=>{
console.log('clicked')
this.setState=({List: this.state.List.concat(this.state.input)})
}
render (){
return (
<div className="App">
<h1>TODO LIST</h1>
<input onChange={this.onAddChange} type='text' placeholder='Add Items'/>
<button onClick={this.Onclickadd} className='btn'>Add</button>
<ol>
{this.state.List.map((items, keys) => {
return <li key={keys}> {items}</li>
})}
</ol>
</div>
);
}
}
export default App;
this.setState is an function witch expects an object, you are trying to assign the value, instead off this.setState= use;
this.setState({
input: event.target.value
})
class App extends React.Component {
constructor(){
super()
this.state={
List: ['potato']
}
}
onAddChange=(event)=>{
this.setState({
input: event.target.value
})
}
Onclickadd=()=>{
this.setState({List: this.state.List.concat(this.state.input)})
}
render (){
return (
<div className="App">
<h1>TODO LIST</h1>
<input onChange={this.onAddChange} type='text' placeholder='Add Items'/>
<button onClick={this.Onclickadd} className='btn'>Add</button>
<ol>
{this.state.List.map((items, keys) => {
return <li key={keys}> {items}</li>
})}
</ol>
</div>
);
}
}
ReactDOM.render(<App />, document.body);
<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>
More info about setState can be found here
this.setState=... is the issue in your code. It is a function call there is no assignment using =.
You have done the same mistake in two places
Change the onAddChange to
onAddChange=(event)=>{
this.setState({
input: event.target.value
})
}
and
Onclickadd to
Onclickadd=()=>{
console.log('clicked')
this.setState({List: this.state.List.concat(this.state.input)})
}
Working example => https://codesandbox.io/s/intelligent-galois-ih7w4?file=/src/App.js:294-418
I recommend you to add value={this.state.input} to the input like following :
<input value={this.state.input} onChange={this.onAddChange} type='text' placeholder='Add Items'/>
The syntax of this.setState() is not right, it's like this :
this.setState({ List: this.state.List.concat(this.state.input) })
this.setState({ input: event.target.value })

Value of Form Input not updating on Submit in React

I am new to React and writing a basic program where using two input fields and a button I want to show the submitted data through another component.
I have declared state in the App component and used a handleChange and handleSubmit method. I have used this state data as props in Display component. But I am getting the data shown when input changes and not on submit.
Have a look at my code:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(){
super();
this.state={
first:'',
last:''
}
this.handleChange=this.handleChange.bind(this);
//this.handleSubmit=this.handleSubmit.bind(this);
}
//handleChange method will capture the change in the values of input field
//Here [e.target.name]:e.target.value will set the input value to name="first" and name="last"
handleChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit(e){
e.preventdefault();
this.handleChange();
}
render() {
return (
<div className="App">
<div class="row">
<input name="first" onChange={this.handleChange}type="text" value={this.state.first}></input>
</div>
<div class="row">
<input name="last" onChange={this.handleChange}type="text" value={this.state.last}></input>
</div>
<div class="row">
<input name="submit" type="button" onSubmit={this.handleSubmit}></input>
</div>
<Display name={this.state.first} last={this.state.last}/>
</div>
);
}
}
const Display=(props)=>{
return(
<div>
<div class="row">
{props.name}
</div>
<div class="row">
{props.last}
</div>
</div>
)
}
export default App;
Also can somebody explain me why do we write [e.target.name]:e.target.value
in setState and why do we right it as []?
The handleChange function that you have used sets the state to first and last states respectively when they change. This pattern is called Controlled Components in React.
On why we use [] in the handleChange function, as you have already pointed out in comments of your code, it is to set the state to first and last, which are also name properties of your inputs. This syntax is called Computed Property and you can find explanation on this in React docs.
If you want the Display component to pick up the state only when you press submit, the alternative is to maintain two separate states for them. One is for the form and another one is for the validated one that is displayed.
Demo:
const { Component } = React;
class App extends Component {
constructor(){
super();
this.state={
first:'',
last:''
}
this.handleSubmit=this.handleSubmit.bind(this);
}
handleSubmit(first, last){
this.setState({
first,
last,
})
}
render() {
return (
<div className="App">
<Form onSubmit={this.handleSubmit} />
<Display name={this.state.first} last={this.state.last}/>
</div>
);
}
}
class Form extends Component {
constructor(){
super();
this.state={
first:'',
last:''
}
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
this.props.onSubmit(this.state.first, this.state.last);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="row">
<input name="first" onChange={this.handleChange}type="text" value={this.state.first} />
</div>
<div className="row">
<input name="last" onChange={this.handleChange}type="text" value={this.state.last} />
</div>
<div className="row">
<input name="submit" type="submit" />
</div>
</form>
);
}
}
const Display=(props)=>{
return(
<div>
<div className="row">
{props.name}
</div>
<div className="row">
{props.last}
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>

All checkbox are checked upon clicking

I'm fairly new to react, and I'm trying to create a simple form. The form app has many elements including the 3 checkbox. And to simplify my issue, I'm only showing the checkboxes. Here what I'm doing
When I click on a checkbox, the value of the label will be pushed
into an array and saved into the App state.
I'm using event.target.name because I have multiple inputs in the
form and I wanted to keep just in case to make my problem more
descriptive.
When I click on submit, it should clear the checkbox.
The problem is when I click on checkbox all the 3 of get checked and it won't be cleared after hitting submit. Is there any way to overcome this? or why its happening?
function CheckBox(props) {
var style= {
padding:10,
marginLeft:5
}
return(
<div style={style} >
{props.checkboxList.map((item,index) =>
<div key={index}>
<input type="checkbox"
onChange={props.changeHandler}
checked={props.checkStatus} name={props.name} value={item.val} />
<label>{item.num}) {item.val}</label>
</div>)}
</div>
)
}
class App extends React.Component{
constructor(props) {
super(props);
this.state={item:[],checked:false}
this.changeHandler=this.changeHandler.bind(this)
this.submitHandler=this.changeHandler.bind(this)
}
changeHandler(event) {
if(event.target.name=="choice") {
var arr=this.state.item.slice()
arr.push(event.target.value)
this.setState({item:arr, checked:event.target.checked}, ()=> console.log(this.state.item +"--"+ this.state.checked))
}
else{ console.log('error')}
}
submitHandler(){
this.setState({item:[],checked:false})
}
render() {
return(
<div>
<CheckBox checkboxList={[
{num:"a", val:"choice 1"},
{num:"b", val:"choice 2"},
{num:"c", val:"choice 3"}]} changeHandler={this.changeHandler} name="choice" checkStatus={this.state.checked} />
<button onClick={this.submitHandler}>Submit</button>
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
<div id="root"></div>
The main approach is to add state key to the each checkbox:
constructor(props) {
super(props);
this.state={item:[],checked:{}}
this.changeHandler=this.changeHandler.bind(this)
this.submitHandler=this.submitHandler.bind(this)
}
changeHandler(event) {
if(event.target.name=="choice") {
var arr=this.state.item.slice()
arr.push(event.target.value)
this.setState({item:arr, checked:{
...this.state.checked,
[event.target.value]: event.target.checked
}}, ()=> console.log(this.state.item +"--"+ this.state.checked))
}
else{ console.log('error')}
}
submitHandler(){
this.setState({item:[],checked:{}})
}
and for checkbox:
{props.checkboxList.map((item,index) =>
<div key={index}>
<input type="checkbox"
onChange={props.changeHandler}
checked={props.checkStatus[item.val]} name={props.name} value={item.val} />
<label>{item.num}) {item.val}</label>
</div>)}

Unable to delete list item in react. Error shows: Uncaught TypeError: Cannot read property 'remove' of undefined

I'm trying to make simple todo app.In this i want delete item from list by onClick function. The button onClick returns function named remove(i) which deletes the item in list. But I'm getting error as mentioned above.
The code is as follows:
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor(){
super();
this.state={
todo:[]
};
};
entertodo(keypress){
var todo=this.refs.newtodo.value;
if( keypress.charCode == 13 )
{
this.setState({
todo: this.state.todo.concat(todo)
});
this.refs.newtodo.value=null;
};
};
todo(data,i){
return (
<li key={data.id} index={i}>
<input type="checkbox"className="option-input checkbox"/>
<div className="item">
{data}
<button onClick={this.remove.bind(this)}className="destroy"></button>
</div>
</li>
);
};
remove(i){
var todo=this.refs.newtodo.value;
var deletetodo=this.state.todo.concat(todo)
deletetodo.splice(i,1);
this.setState({todo:deletetodo})
};
render() {
return (
<div>
<div className="lines"></div>
<div>
<input type="text" ref= "newtodo" onKeyPress={this.entertodo.bind(this)}className="inputext"placeholder='todos'/>
</div>
<div className="app">
<ul>
{this.state.todo.map(this.todo.bind(this))}
</ul>
</div>
</div>
);
}
}
export default App;
The same problem arises if i try to call a function for to strikeoff the list item upon click on checkbox. Need help.
You need to bind your todo and remove function and also need to splice your todo array correctly. As your ref new is not defined and unique, you cannot access the value so just splice the array by index
class App extends React.Component {
constructor(){
super();
this.state={
todo:[]
};
};
entertodo(keypress){
var todo=this.refs.newtodo.value;
if( keypress.charCode == 13 )
{
this.setState({
todo: this.state.todo.concat(todo)
});
this.refs.newtodo.value=null;
};
};
todo = (data,i) => {
return (
<li>
<input type="checkbox"className="option-input checkbox"/>
<div key={data.id} className="item">
{data}
<button onClick={this.remove.bind(this, i)}className="destroy">Delete</button>
</div>
</li>
);
};
remove = (i) =>{
var deletetodo = {...this.state.todo};
this.state.todo.splice(i,1);
this.setState({todo:this.state.todo})
};
render() {
return (
<div>
<div className="lines"></div>
<div>
<input type="text" ref= "newtodo" onKeyPress={this.entertodo.bind(this)}className="inputext"placeholder='todos'/>
</div>
<div className="app">
<ul>
{this.state.todo.map(this.todo)}
</ul>
</div>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

How to push values into state by calling single onChange function - react

I am new to reactive. I am working on react+flux+alt with ES6.
I have a form for creating new record.
Component
import React from 'react';
import { Input, Button, Glyphicon, ButtonToolbar } from 'react-bootstrap';
import AttributeSectionStore from 'stores/attributeSection/AttributeSectionStore';
import TextBoxesSet from '../descriptionTextBoxes';
import styles from 'scss/_common';
export default class AttributeSection extends React.Component {
constructor(props) {
super(props);
}
_onCreate = () => {
console.log('___________', this.state);
}
onChangeName = (evt) => {
this.setState({name: evt.target.value});
};
onChangeRank = (evt) => {
this.setState({rank: evt.target.value});
};
static getPropsFromStores() {
return recordStore.getState();
}
render() {
return (
<div className="container">
<div className={styles.mainheader}>
<h2 >New Record</h2>
</div>
<div className="col-md-9">
<form className="form-horizontal">
<div className="row">
<div className="col-md-12">
<Input type="text" label="Name" labelClassName="col-xs-2"
wrapperClassName="col-xs-4" value={this.props.name}
onChange={this.onChangeName}/>
</div>
</div>
<div className="row">
<div className="col-md-12">
<Input type="number" label="Rank" labelClassName="col-xs-2"
wrapperClassName="col-xs-4" value={this.props.rank}
onChange={this.onChangeRank}/>
</div>
</div>
<div className="row">
<div className="col-md-4 col-md-offset-2">
<ButtonToolbar className={styles.formBtnGrp}>
<Button bsStyle="primary" onClick={this._onCreate}>Create</Button>
<Button type="reset">Cancel</Button>
</ButtonToolbar>
</div>
</div>
</form>
</div>
</div>
);
}
}
AttributeSection.propTypes = {
name: React.PropTypes.string
rank: React.PropTypes.number
};
Using above component now I'm getting data into state but form may have more than 2 fields. I'm using two functions to update state instead of that how can use single function to update state object?Is there any other best practice is there?
The most common pattern to solve this is using bind() to curry a value to the onchange callback. This is was #knowbody referenced (React.js: Identifying different inputs with one onChange handler)
An alternate, but similar, pattern is adding a second tag within the element to identify the name of the state property to change. I'll show an example using label from your code (obviously you want to use a dedicated tag since label is for display and would be localized).
onInputChanged(evt) {
var newState = this.state,
propName = evt.target.label.toLowerCase();
newState[propName] = evt.target.value;
this.setState(newState);
};

Resources