Hide an element in multiple elements by react - reactjs

I want to hide an element by react in multiple elements. I try to use isHidden: true, but when i click the close button instead of hiding selected element, gives me a full blank page ? why?
class App extends React.Component {
constructor(props){
super(props);
this.state = {
data: [
{ _id: "5bb85a2be138230670c3687b", firstName: "foo", lastName: "foo", email: "foo#foo.com"},
{ _id: "5bb9b3cae13823261e886990", firstName: "bar", lastName: "bar", email: "bar#bar.com" },
],
editVisibles: {},
isHidden: true,
};
}
showEditDiv = (_id) => {
this.setState( prevState => ({
editVisibles: { ...prevState.editVisibles, [_id]: !prevState.editVisibles[_id] }
})
)
};
toggleHidden = ()=> this.setState((prevState)=>({isHidden: !prevState.isHidden}))
renderFlight() {
return this.state.data.map(item => {
return (
<div>
{this.state.isHidden &&
<li key={item._id}>
<div class="close" onClick={() => this.toggleHidden(item._id)}>X</div>
<p>{item.email}</p>
<button onClick={() => this.showEditDiv(item._id)}>Edit</button>
<div key={item._id} className={`edit-form ${!this.state.editVisibles[item._id] ? "unvisible" : "visible"}`}>
</div>
</li>
}
</div>
)
})
}
render() {
return (
<div>{this.renderFlight()}</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));

First of all, the code is really messy and hard to read, so you should edit it for better visibility.
Also, notice that isHidden is true when the element should not be visible, but your code states that "if this.state.isHidden is true, then render the content of the div".
What you want is !this.state.isHidden && ...
Also, you should use reduce/filter to filter out the elements that have a truthy value for isHidden, instead of map, because right now you're pushing empty div elements which is unnecessary

Could see an argument in your method call - this.toggleHidden(item._id), but item._id is not used in the function definition. Any particular reason for that?
toggleHidden = ()=>
this.setState((prevState)=>({isHidden: !prevState.isHidden
}))
Basically we have to select the item by keyProp and apply the toggle method. Go through
How to find element by Key in React?
<li keyProp={'listItem_'+item._id}>
would give the necessary attribute and we can apply show/hide on the li element by selecting using props.keyProp

Related

how to push a new element into an array from the state

I'm trying to push in elements into an array called 'this.state.tags'. On the console, I see the elements pushing into the array. However, when I add something, the array comes out blank, when I add more items I only the see the previous items I've added. I'm not seeing the newest item I've pushed in.
I've done Object.assign([], this.state.tags) from the child component Grades.js. Then I pushed in 'this.state.newTag' and I've reset the state to that new result.
//From Grades.js, the child component
state = {
toggle: null,
newTag: '',
tags: []
}
addTags = (event) => {
event.preventDefault();
let newTagArr = Object.assign([], this.state.tags)
newTagArr.push(this.state.newTag)
this.setState({
tags: newTagArr
})
// this will pass on to the parent
this.props.filterTags(this.state.tags)
}
render() {
const { tags } = this.state
let tagList = tags.map((item, index) => {
return (
<li key={index} className="tagListItem">{item}</li>
)
})
return(
<div>
<ul className="tagList">{tagList}</ul>
<form onSubmit={this.addTags}>
<input
placeholder="Add a tag"
name="newTag"
onChange={this.handleInput}
style={{border: '0', borderBottom: '1px solid #000'}}
/>
</form>
</div>
)
}
// From App.js, the parent component
state = {
students: [],
filteredStudents: [],
filteredByTag: [],
search: '',
tag: '',
toggle: false
}
componentDidMount() {
axios.get('https://www.hatchways.io/api/assessment/students')
.then(result => {
let newArr = Object.assign([], result.data.students);
let newResult = newArr.map(elem => {
return {city: elem.city, company: elem.company, email: elem.email,
firstName: elem.firstName.toLowerCase(), lastName: elem.lastName.toLowerCase(),
grades: elem.grades, id: elem.id, pic: elem.pic, skill: elem.skill}
})
this.setState({
students: newResult
})
})
.catch(err => console.log(err))
}
tagFiltering = (param) => {
console.log(param)
this.state.students.push()
}
I expect the output to be ["tag1", "tag2", "tag3"]
Not ["tag1", "tag2"], when I've already typed in tag1, tag2 and tag3
Use ES2015 syntax :
this.setState({
tags: [...this.state.tags , this.state.newTag]
})
In react the state is immutable meaning that we have to provide new state object every time, we call the setState method.

How can I update certain object in state with new data

I am making a notes taking application with React, when I click on a note in sidebar it opens in content area, then while changing text it updates the notes state, updates the current opened note with the current content inside the input area.
Can I do it with spread operator?
here is the full code on codesandbox
class App extends React.Component {
constructor() {
super();
this.state = {
notesList: [
{key: 0, title: "title of first note", note: "this is the first note"},
{key: 1, title: "title of second note", note: "this is another note"}
],
inputValue: null,
currentKey: null
};
}
noteTitleClicked = value => {
this.setState({
inputValue: value.note,
currentKey: value.key
});
};
updateNoteDetails = e => {
this.setState({
inputValue: e.target.value
});
};
render() {
const notes = this.state.notesList.map(note => (
<li key={note.key} onClick={e => this.noteTitleClicked(note)}>
{note.title}
</li>
));
const inputValue = this.state.inputValue;
return (
<div className="App">
<header>Header</header>
<div className="main">
<article>
{inputValue == null ? (
""
) : (
<input
className="noteDetails"
value={this.state.inputValue}
onChange={this.updateNoteDetails}
/>
)}
</article>
<nav>
<ul>{notes}</ul>
</nav>
</div>
<footer>Footer</footer>
</div>
);
}
}
Try this:
updateNoteDetails = e => {
const updated = this.state.notesList.map(n => {
if (n.key === this.state.currentKey)
return { ...n, note: e.target.value };
return n;
});
this.setState({
inputValue: e.target.value,
notesList: updated
});
};
This this is the demo: https://codesandbox.io/s/k591vor8v3

How to update state in map function in reactjs

I am having 4 buttons each button have name id and selected boolean flag.
What I am trying to achieve is, on click of button, boolean button flag should be changed of that particular button. For this, I need to setState in map function for that particular button Id.
My issue is I am unable to setState in map function for that particular clicked button, its btnSelected should be changed
My aim is to create a multi-select deselect button.Its kind of interest selection for the user and based on that reflect the UI as well my array. Here is my code.
Thanks in anticipation.
import React, { Component } from "react";
import { Redirect } from "react-router-dom";
export default class Test extends Component {
constructor(props, context) {
super(props, context);
this.handleChange = this.handleChange.bind(this);
this.state = {
value: "",
numbers: [1, 2, 3, 4, 5],
posts: [
{
id: 1,
topic: "Animal",
btnSelected: false
},
{
id: 2,
topic: "Food",
btnSelected: false
},
{
id: 3,
topic: "Planet",
btnSelected: false
},
{ id: 4, topic: "Nature", btnSelected: false }
],
allInterest: []
};
}
handleChange(e) {
//console.log(e.target.value);
const name = e.target.name;
const value = e.target.value;
this.setState({ [name]: value });
}
getInterest(id) {
this.state.posts.map(post => {
if (id === post.id) {
//How to setState of post only btnSelected should change
}
});
console.log(this.state.allInterest);
if (this.state.allInterest.length > 0) {
console.log("Yes we exits");
} else {
console.log(id);
this.setState(
{
allInterest: this.state.allInterest.concat(id)
},
function() {
console.log(this.state);
}
);
}
}
render() {
return (
<div>
{this.state.posts.map((posts, index) => (
<li
key={"tab" + index}
class="btn btn-default"
onClick={() => this.getInterest(posts.id)}
>
{posts.topic}
<Glyphicon
glyph={posts.btnSelected === true ? "ok-sign" : "remove-circle"}
/>
</li>
))}
</div>
);
}
}
Here's how you do something like this:
class App extends Component {
state = {
posts: [{
name: 'cat',
selected: false,
}, {
name: 'dog',
selected: false
}]
}
handleClick = (e) => {
const { posts } = this.state;
const { id } = e.target;
posts[id].selected = !this.state.posts[id].selected
this.setState({ posts })
}
render() {
return (
<div>
<form>
{this.state.posts.map((p, i) => {
return (
<div>
<label>{p.name}</label>
<input type="radio" id={i} key={i} checked={p.selected} onClick={this.handleClick} />
</div>
)
})}
</form>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Working example here.
You can do this by passing the index from the map into each button's handleClick function, which would then return another function that can be triggered by an onClick event.
In contrast to Colin Ricardo's answer, this approach avoids adding an id prop onto each child of the map function that is only used for determining the index in the handleClick. I've modified Colin's example here to show the comparison. Notice the event parameter is no longer necessary.
class App extends Component {
state = {
posts: [{
name: 'cat',
selected: false,
}, {
name: 'dog',
selected: false
}]
}
handleClick = (index) => () => {
const { posts } = this.state;
posts[index].selected = !this.state.posts[index].selected
this.setState({ posts })
}
render() {
return (
<div>
<form>
{this.state.posts.map((p, i) => {
return (
<div>
<label>{p.name}</label>
<input type="checkbox" key={i} checked={p.selected} onClick={this.handleClick(i)} />
</div>
)
})}
</form>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Working example here

Toggle button onclick in react

I am making a table in react, where I want to change the edit button to save when I click on it. I have tried the below code, I know this isn't the correct way. Can anyone tell me what is the correct approach?
This is the edit button in render. It calls edit function when clicked.
dataProp contains the json data I am importing from a file.
{this.state.dataProp.map((data, index) => {
return (
<div className="show-grid row category-row">
<div className="col-md-8 text-left category" key={data.brandId}>
<b>{data.categoryName}</b></div>
<div className="col-md-4 text-right" >
<button className="edit" ref="newText" onClick={() =>
this.edit(index)}>{this.state.text}</button>
</div>
</div>
</div>
)
})}
class DisplayTable extends Component {
constructor(props) {
super(props);
this.state = {
text: "EDIT",
newArray: [],
dataProp: this.props.dataProp,
productsEditList:[ ---->This is for toggling individual button
{
id: 0,
isEdit: false
},
{
id: 1,
isEdit: false
},
{
id: 2,
isEdit: false
}
]
}
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
edit(key) {
this.state.productsEditList.map(keyy => {
if (key == keyy.id) {
keyy.isEdit:true
}
this.save(key);
})
}
save(key) {
if (!this.state.editing.key) {
this.setState({
text: 'SAVE',
editing: false
})
}
}
This code causes all the buttons change to save when I click on any one of them.
I do not understand how should I toggle individual buttons.
all buttons changes to save when I click on anyone of them
I took the text of the button in a state and toggled it whenever my button is clicked.
Here is the code for button -
<button className={this.state.text === "EDIT" ? "edit" : "save"} onClick={() =>this.edit}>{this.state.text}
</button>
Here is code for toggling the button
edit() {
if (this.state.editing === false) {
this.setState({
text: 'SAVE',
editing: true
});
}
else {
this.setState({
text: 'EDIT',
editing: false
});
if (this.state.changedSkus.length > 0) {
this.props.edit_menu_items_api({ "changedSkus": this.state.changedSkus });
}
}
this.render();
}

Inputs not changing when removing list items from state

I made a simple class that shows a list that you can add or remove li items into state. However, these li items contains input boxes.
Let's say there are 3 li items with 3 input boxes in it. You type something into first list item's input box, then you want to remove that li which contains your filled input.
Even if my index is correct react removes always the last item or I thought it removes the last item, maybe it removes the exact one with the correct index but preserves inputs' values. how can I fix this thing?
class DataTable extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{product: 'a', quantity: 0, price: 0},
],
};
}
render() {
if (!this.props.isOpen) {
return false;
}
const items = this.state.data.map((key, i) => {
return (
<li key={i}>
<input name="text" defaultValue={key.product}/>
<buttun className="btn" onClick={this.removeItem.bind(this, i)}/>
</li>
)
})
return (
<div>
<button className="btn" onClick={this.addItem.bind(this)}>Add Product</button>
<ul>
{items}
</ul>
</div>
)
}
addItem() {
const newState = update(this.state.data, {
$push: [{product: '', quantity: 0, price: 0}]
});
this.setState({
data: newState
})
}
removeItem(index) {
const newArray = update(this.state.data, {
$splice: [[index, 1]]
});
this.setState({
data: newArray
})
}
}
export default DataTable
Don't know if this is your problem but you are using the index of data as the key. This is only fine to do so when you don't modify the collection. Key must stay constant throughout, what's happening is that you remove an item and add another one and React thinks that input is the other one because it's key has changed.
constructor(props) {
super(props);
this.state = {
data: [
{product: 'a', quantity: 0, price: 0},
],
};
this.dataKey = 0;
render() {
if (!this.props.isOpen) {
return false;
}
const items = this.state.data.map((value) => {
return (
<li key={value.key}>
<input name="text" defaultValue={value.product}/>
<buttun className="btn" onClick={this.removeItem.bind(this, i)}/>
</li>
)
})
return (
<div>
<button className="btn" onClick={this.addItem.bind(this)}>Add Product</button>
<ul>
{items}
</ul>
</div>
)
addItem() {
const newState = update(this.state.data, {
$push: [{product: '', quantity: 0, price: 0, key: this.dataKey++}]
});
this.setState({
data: newState
})
}
removeItem(index) {
const newArray = update(this.state.data, {
$splice: [[index, 1]]
});
this.setState({
data: newArray
})
}
}
It just has to be something that is unique and constant. An Id for example would be good for this. https://facebook.github.io/react/docs/lists-and-keys.html

Resources