ReactJS two way binding not working, somewhere wrong with binding - javascript

I'm new to reactJs, I'm not sure where it went wrong.
I suppose there is something wrong with binding input. I suppose, cant change input because of value={detail.name}. However, even though I have deleted value={detail.name}, Name: {detail.name} still keeps the original value.
Could somebody give me a hint?
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
]
};
}
changeName(event) {
this.setState({
name: event.target.value
});
}
onDelete() {}
render() {
return (
<div>
<ul>
{this.state.details.map((detail, index) => (
<li key={index}>
Name: {detail.name} | age: {detail.age}
<input
style={{ marginLeft: "10px" }}
type="text"
onChange={this.changeName.bind(this)}
value={detail.name}
/>
</li>
))}
</ul>
</div>
);
}
}
export default App;

I updated the code a bit.
First of all, I moved the binding of the callback to the constructor (to have ONE callback instead of one per item*render)
I also changed the key used in the map to be the id, rather than the index of the current item.
Try, it, I hope it works for you.
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
]
};
this.changeName = this.changeName.bind(this);
}
changeName(event) {
const {target} = event;
const id = Number(target.dataset.id);
const { details } = this.state;
this.setState({
details: details.map((detail) => {
if (detail.id === id) {
return {
...detail,
name: target.value,
}
}
return detail;
}),
});
}
onDelete() {}
render() {
return (
<div>
<ul>
{this.state.details.map(({ id, age, name }) => (
<li key={id}>
Name: {name} | age: {age}
<input
style={{ marginLeft: "10px" }}
type="text"
onChange={this.changeName}
data-id={id}
value={name}
/>
</li>
))}
</ul>
</div>
);
}
}
export default App;

Your code works fine, nothing wrong with the input data binding. The problem is you're setting the name property directly to the state object. That would make it go from this:
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
]
}
To this:
this.state = {
details: [
{ id: 1, name: "Tom", age: "20" },
{ id: 2, name: "zhunan", age: "22" },
{ id: 3, name: "kobe", age: "35" }
],
name: "Bob"
}
Which has no effect on how the component gets rendered. To properly change the name of one of the details, which is what I assume you want, you also need to do a find that detail object to modify. Like this:
changeName(e, target_detail) {
this.setState({
// always update the WHOLE STATE OBJECT! using a map
details: this.state.details.map(detail => {
// the detail we want to modify has the same ID
if(detail.id === target_detail.id) {
// modify the name value of only that
target_detail.name = e.target.value
}
})
});
}
render method:
render() {
return (
<div>
<ul>
{this.state.details.map((detail, index) => (
<li key={index}>
Name: {detail.name} | age: {detail.age}
<input
style={{ marginLeft: "10px" }}
type="text"
// arrow functions implicitly "bind" the current this context:
onChange={e => this.changeName(e, detail)}
value={detail.name}
/>
</li>
))}
</ul>
</div>
);
}

Related

React JS. How can I display the image inside the object?

How can I display the image inside the object in React.js?
const Area = () =>{
const flags = [
{ id: 1, name: "USA", image: "./us.png" },
{ id: 2, name: "Canada", image: "./ca.png" },
];
return (
<div>
{flags.map((area) => {
return <img key={area.id} src={area.image} />;
})}
</div>
)}
The very first thing that you need to do is wrap the src in {} which you're doing already.
Then if you're using webpack. Instead of : <img src={"./us.png"} />
You need to use require() like this <img src={require('./us.png')} />
const Area = () => {
const flags = [
{ id: 1, name: "USA", image: "./us.png" },
{ id: 2, name: "Canada", image: "./ca.png" },
]
return (
<div>
{flags.map((area) => {
return <img key={area.id} src={require(area.image)} />;
})}
</div>
)}
}
Another option would be to first import the image as shown below
import ca from './us.png' or const us = require('./us.png).
Then add them to your flags object like shown below:
import usa from './us.png;
import canada from './ca.png;
const Area = () => {
const flags = [
{ id: 1, name: "USA", image: usa },
{ id: 2, name: "Canada", image: canada },
]
return (
<div>
{flags.map((area) => {
return <img key={area.id} src={area.image} />;
})}
</div>
)}
}
You can use require for images inside an object.But your code works fine even without that you just have to return it inside return method().
const Area = () =>{
const flags = [
{ id: 1, name: "USA", image: require('./us.png') },
{ id: 2, name: "Canada", image: require('./ca.png') },
]
return (
<div>
{flags.map((area) =>
<img key={area.id} src={area.image} />
)}
</div>
)
}
return(
Area()
)
It works fine this way as well
const Area = () =>{
const flags = [
{ id: 1, name: "USA", image: "./us.png" },
{ id: 2, name: "Canada", image: "./ca.png" },
]
return (
<div>
{flags.map((area) =>
<img key={area.id} src={area.image} />
)}
</div>
)
}
return(
Area()
)
As I mentioned in my comments that please double check the path of the image. Image path might be a problem else it is looking fine. Moreover, you can press ctrl+click on path to route to that folder or check it manually.

Filling a model with a list from Textarea

Now I do not really understand you. Sorry, I just started this whole study not so long ago. I’ll try to explain again what I can’t do.
I have an empty object and an object with data with the same structure.
data: [
{id: 1, title: "title1"},
{id: 2, title: "title1"},
{id: 3, title: "title3"},
{id: 4, title: "title4"},
{id: 5, title: "title3"}
],
item: [
{
itemId: "",
itemname: ""
}
]
And I have select and textarear. Select have data, textarear empty. Textarear displays title.
I want to press a button. Selected item from select. copied to textarear (title only), and also itemId - this selected element id: 5 and itemname - the same title: "title3" element, was recorded in item [].
https://codesandbox.io/s/priceless-hermann-g9flw
Please do check now
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
id: null,
title: "",
filmItem: "",
listFilms: [],
data: [
{ id: 1, title: "title1" },
{ id: 2, title: "title2" },
{ id: 3, title: "title3" },
{ id: 4, title: "title4" }
],
item: []
};
this.onChange = this.onChange.bind(this);
this.onChangeArea = this.onChangeArea.bind(this);
this.addFilm = this.addFilm.bind(this);
this.choice = this.choice.bind(this);
}
addFilm(film) {
const selectedData = this.state.data.find(item => item.id == film);
console.log(selectedData);
this.setState({
listFilms: [...this.state.listFilms, selectedData.title],
item: [
...this.state.item,
{ itemId: selectedData.id, itemname: selectedData.title }
]
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onChangeArea = e => {
this.setState({ [e.target.name]: e.target.value.split("\n") });
};
choice(title) {
this.setState({ filmItem: title });
}
render() {
return (
<div className="App">
<div className="row App-main">
<div>
<select name="filmItem" size="4" onChange={e => this.onChange(e)}>
{this.state.data.map(film => (
<option key={film.title} value={film.id}>
{film.title}
</option>
))}
</select>
</div>
<div>
<button
className="editButton"
onClick={() => this.addFilm(this.state.filmItem)}
>
button
</button>
</div>
<div>
<textarea
name="films"
onChange={this.onChangeArea}
value={this.state.listFilms.map(r => r).join("\n")}
/>
</div>
<div>
<input type="text" name="text-input" onChange={this.onChange} />
</div>
</div>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(this.state)}
</pre>
</div>
);
}
}
export default App;

Creating multi switches dynamically using React-switch

I am having a list of data, which i displayed in the frontend using map function. Each data will have an switch button. If a user clicks on a particular, it will display an description regarding the data below. Now, if i use static data. it switch working properly. But all get selected at the same time. I want only the particular one to get select, when i click the particular one. I am using react-switch library for the switch. Below is my code, Pleasse check and let me know, how cal I achieve that.
/***Parent Component***/
import React, { Component } from "react";
import ReqLists from "./ReqLists";
class Requirements extends Component {
constructor(props) {
super(props);
this.state = {
reqs: [
{
id: 0,
name: "Application",
details: "Do you require an application from volunteers?"
},
{ id: 1, name: "Screening Questions", details: "", description: "Dummy content" },
{
id: 2,
name: "Recurring commitment",
details:
"Does this opportunity require a recurring commitment from volunteers?", description: "Dummy content"
},
{ id: 3, name: "Documents for volunteers to upload ", details: "", description: "Dummy content" },
{ id: 4, name: "Waiver & Release of Liability Forms", details: "", description: "Dummy content" },
{ id: 5, name: "Parental Consent & Medical Form", details: "", description: "Dummy content" },
{ id: 6, name: "Age", details: "", description: "Dummy content" },
{ id: 7, name: "Certifications", details: "", description: "Dummy content" },
{ id: 8, name: "Languages", details: "", description: "Dummy content" },
{ id: 9, name: "Skils", details: "", description: "Dummy content" },
{ id: 10, name: "Additional Requirements", details: "", description: "Dummy content" },
{ id: 11, name: "Additional Details", details: "", description: "Dummy content" }
],
checked: 0
};
}
handleChange = id => {
const checked = this.state.checked;
checked[id] = checked.hasOwnProperty(id) ? !checked[id] : true;
this.setState({ checked });
};
render() {
return (
<div style={{ width: "100%" }}>
<ReqLists
lists={this.state.reqs}
onChange={this.handleChange}
checked={this.state.checked}
/>
</div>
);
}
}
export default Requirements;
/***Child Component***/
import React, { Component } from "react";
import { withStyles, Typography } from "#material-ui/core";
import Switch from "react-switch";
class ReqLists extends Component {
render() {
const { lists, classes } = this.props;
return (
<div className={classes.reqWrapper}>
{lists &&
lists.map(list => {
return (
<div className={classes.reqCover} key={list.id}>
<div className={classes.reqDetails}>
<Typography className={classes.reqListName}>
{list.name}
<span className={classes.reqListDetails}>
{list.details}
</span>
</Typography>
<Switch
className={classes.reqSwitch}
onChange={() => this.props.onChange(list.id)}
checked={this.props.checked === list.id}
offColor="#cacaca"
onColor="#2299e9"
uncheckedIcon={
<div className={classes.checkedIcon}>NO</div>
}
checkedIcon={<div className={classes.checkedIcon}>YES</div>}
height={17}
width={35}
/>
</div>
{this.props.checked === list.id ? (
<div>
{list.description}
</div>
) : null}
</div>
);
})}
</div>
);
}
}
export default withStyles(styles)(ReqLists);
Change your handleChange method with this: All you need to check if the selected id is not equals to checked id update checked state.
handleChange = id => {
let selectedItemIndex = this.state.reqs.findIndex(item => item.id === id);
if (selectedItemIndex !== this.state.checked) {
this.setState({checked: selectedItemIndex});
}else{
this.setState({checked: null});
}
};

Issue with dismissing item in reactjs

I am trying to dismiss an item from my array which I have mapped out. I made the onclick button, binded it, and defined the function. However, when I press the dismiss button, the items are still there
I tried to change my object id to different name, change some of the code. I even console.log to see whether my button was working. It was. Just it wasnt deleting the intended item.
import React from "react";
import "./App.css";
const animals = [
{ id: 1, species: "Bear", habitat: "Mountains" },
{ id: 2, species: "Lion", habitat: "Sahari" },
{ id: 3, species: "Hippo", habitat: "Sahari" },
{ id: 4, species: "Eagle", habitat: "Trees" },
{ id: 5, species: "Fish", habitat: "River" },
{ id: 6, species: "Snake", habitat: "Desert" },
{ id: 7, species: "Alligator", habitat: "Everglades" },
];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: animals
}
this.onDismiss = this.onDismiss.bind(this);
}
onDismiss(id) {
const isNotID = animal => animal.id !== id;
const updatedList = this.state.animals.filter(isNotID);
this.setState({animals: updatedList});
console.log(this.state.animals)
}
render() {
return(
<div className="App">
{
animals.map((animal)=> {
return (
<div key={animal.id}>
<div>{animal.species}</div>
<div>{animal.habitat}</div>
<span>
<button onClick={()=>this.onDismiss(animal.id)}>Dismiss</button>
</span>
</div>
)
})
}
</div>
);
}
}
export default App;
I want the item to be deleted once i press the dismiss button. And bring back the updated list which will be brought about from the setState
Your render method is using animals (your initial data) instead of this.state.animals.

Rendering button inside a list

How would one go about rendering a button with a click event inside of a list? I am not sure why I cannot render a button next to each dog in the list and add that dog to my cart array. I know I am missing something here because whenever I add a function to an onClick event I must get an error because my entire interface disappears. Say I have a component:
var PetStore = React.createClass({
getInitalState: function() {
return ({
cart: []
})
},
addToCart: function(dog) {
this.setState({
cart: this.state.cart.concat([dog])
})
},
render: function() {
return (
<ul>
{this.props.dogs.map(function(dog){
return <li>Breed: {dog.breed}, age: {dog.age}
<button onClick={this.addToCart}>Buy</button></li>
})}
</ul>
)
}
})
var DOGS = [{
breed: 'Husky',
age: 5
}, {
breed: 'Pit bull',
age: 2
}, {
breed: 'Golden Retriever',
age: 10
}, {
breed: 'Black lab',
age: 2
}]
var PetStore = React.createClass({
propTypes: {
dogs: React.PropTypes.array
},
getInitialState: function() {
return ({
cart: []
})
},
addToCart: function(dog) {
this.setState({
cart: this.state.cart.concat([dog])
})
},
render: function() {
console.log(this.props);
var self = this;
return (
<ul>
{this.props.dogs.map(function(dog, index){
return (<li key={index}>Breed: {dog.breed}, age: {dog.age} <button onClick={self.addToCart.bind(self,dog)}>Buy</button></li>)
})}
</ul>
)
}
})
ReactDOM.render(<PetStore dogs={DOGS}/>, document.getElementById('test'));

Categories

Resources