How to add an object in an array of objects? ReactJS? - reactjs

My Project is, an array of objects where i get only the names and render on screen of form 3 in 3, with button next and previous change the names, and can to filter for letters.
I would want add a new value, typped on input and clicked in the button add.
My code button:
addItem = () => {
const inValue = {
id: 0,
name: this.state.input
}
this.setState({
filtered: this.state.filtered.concat(inValue),
currentPage: 0
})
}
I would want the value inserted in the filtered array.
My code all:
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
const peoples =[{id:0, name:"Jean"},
{id:1, name:"Jaha"},
{id:2, name:"Rido"},
{id:3, name:"Ja"},
{id:4, name:"Letia"},
{id:5, name:"Di"},
{id:6, name:"Dane"},
{id:7, name:"Tamy"},
{id:8, name:"Tass"},
{id:9, name:"Ts"},
{id:10, name:"Abu"},
{id:11, name:"Ab"}];
this.state = {
elementsPerPage:3,
currentPage:0,
peoples,
input: "",
filtered: peoples,
teste: '',
};
}
getValueInput = (evt) => {
const inputValue = evt.target.value;
this.setState({ input: inputValue });
this.filterNames(inputValue);
}
filterNames = (inputValue)=> {
const { peoples } = this.state;
this.setState({
filtered: peoples.filter(item =>
item.name.includes(inputValue)),
currentPage:0
});
const Oi = this.state.filtered.map(item=>item.name);
if(Oi.length<=0){
alert('Você está adicionando um nome')
}
console.log(Oi)
}
elementsOnScreen = () => {
const {elementsPerPage, currentPage, filtered} = this.state;
return filtered
.map((item) => <li key={item.id}> {item.name} <button onClick={() => this.remove(item.name)}> Delete </button> </li>)
.slice(currentPage*elementsPerPage, currentPage*elementsPerPage + elementsPerPage);
if(this.state.filtered.length < 1){
this.setState({currentPage: this.state.currentPage - 1})
}
}
remove = (id) => {
console.log(this.state.filtered.length)
if(this.state.filtered.length < 0){
this.setState({currentPange: this.state.currenPage - 1})
}
this.setState({filtered: this.state.filtered.filter(item => item.name !== id) })
}
nextPage = () => {
console.log(this.state.filtered)
const {elementsPerPage, currentPage, filtered} = this.state;
if ((currentPage+1) * elementsPerPage < filtered.length){
this.setState({ currentPage: this.state.currentPage + 1 });
}
}
previousPage = () => {
const { currentPage } = this.state;
if(currentPage - 1 >= 0){
this.setState({ currentPage: this.state.currentPage - 1 });
}
}
addItem = () =>{
const inValue = {id:0 ,name: this.state.input}
this.setState({filtered: this.state.filtered.concat(inValue), currentPage: 0})
}
render() {
return (
<div>
<button onClick={this.addItem}> Add </button>
<input type="text" onChange={ this.getValueInput }></input>
<button onClick={this.previousPage}> Previous </button>
<button onClick={this.nextPage}> Next </button>
<h3>Current Page: {this.state.currentPage}</h3>
<ul>Names: {this.elementsOnScreen()}</ul>
</div>
);
}
}
export default App;

You would have the array of objects contained within your state, then use setState
this.state = {
elementsPerPage:3,
currentPage:0,
peoples,
input: "",
filtered: peoples,
teste: '',
peoples: [
{id:0, name:"Jean"},
{id:1, name:"Jaha"},
{id:2, name:"Rido"},
{id:3, name:"Ja"},
{id:4, name:"Letia"},
{id:5, name:"Di"},
{id:6, name:"Dane"},
{id:7, name:"Tamy"},
{id:8, name:"Tass"},
{id:9, name:"Ts"},
{id:10, name:"Abu"},
{id:11, name:"Ab"}];
};
To update the peoples array, you would first need to create a copy of the peoples array, modify the copy, then use setState to update.
let { peoples } = this.state;
peoples.push({ id:12, name:"Jean"})
this.setState({peoples: peoples})

Looks like you are already updating your state with the typed input.
So in your add button you can get the state value and push it to your people array. Something like this:
addItem = () => {
const { inputValue, people } = this.state;
if (!inputValue) return; // check if inputValue has any value
people.push({ id: people.length+1, name: inputValue )} // I don't recommend using sequencial ids like this, you'd better have a handler to generate it for you
this.setState({ people, inputValue: '' }); // update people and clear input
}
Hope it helps

Related

change on of nested array object in react state

i want to replace the values of the nested array object like the below one, when button is clicked it will replace the old values of the x indexed object and set the new values there.
class compo extends React.Component {
constructor() {
super();
this.state = {
tabsData:[
{
id:1,
title:"OldTitle1"
},
{
id:2,
title:"OldTitle2"
}
],
}
this.changeTab = this.changeTab.bind(this)
}
changeTab(){
const newData={
id=3,
title="New One"
}
//replace the above new data in the second object of nested array in state
}
render(){
return(
<button type="button" >Add</button>
)
;}
}
export default compo
the state should be like this after
tabsData:[
{
id:1,
title:"OldTitle"
},
{
id:3,
title:"New One"
}
]
Not able to comment as my rep is less than 50...based on an idea of what you need here is the code.
https://codesandbox.io/s/brave-lumiere-dh9ry?file=/src/App.js
const [data, setData] = React.useState([
{
id: 1,
title: "OldTitle1"
},
{
id: 2,
title: "OldTitle2"
}
]);
const newData = { id: 3, title: "New One" };
const addData = () => {
const newArr = data;
newArr[1] = newData;
console.log("newArr>>>>", newArr);
setData([...newArr]);
};
You could do something like this...
import React from "react";
class compo extends React.Component {
constructor() {
super();
this.state = {
tabsData: [
{
id: 1,
title: "OldTitle1"
},
{
id: 2,
title: "OldTitle2"
}
]
};
this.changeTab = this.changeTab.bind(this);
}
changeTab() {
const newData = {
id: 3,
title: "New One"
};
// Make duplicate since you can't mutatue state
let newTabData = [...this.state.tabsData];
const id = 2; // id to be removed
// CASE 1: If you want to maintain order
const index = newTabData.findIndex((data) => data.id === id);
if (index > -1) {
// replace oldData with newData
newTabData.splice(index, 1, newData);
} else {
// simply add newData at last
newTabData.push(newData);
}
// CASE 2: If order doesn't matter
// // remove oldData
// newTabData = newTabData.filter((data) => data.id !== id);
// // add new data at last
// newTabData.push(newData);
// finally update the state irrespective of any case
this.setState({ tabsData: newTabData });
}
render() {
return (
<div>
<button type="button">
Add
</button>
<button type="button" onClick={this.changeTab}>
Change
</button>
<br />
{JSON.stringify(this.state, null, 2)}
</div>
);
}
}
export default compo;

Change title in this.state

I have this.state with an array, and in array I want to change title, but it is not working. Help me please
Code:
this.state =
{
list: [{title: "1"}, {title: "2"}],
}
// changing title
this.setState({
this.state.list.title: "newTitle"
}],
try this
this.setState({
list: [{title: 'new title'}, { title: 'other title' }]
});
Example
class App extends React.Component {
state = { list: [{title: "1"}, {title: "2"}] };
updateTitle = (index) => {
var { list } = this.state;
list[index].title = `Updated title ${index}`;
this.setState({list});
}
updateTitles = () => {
var { list } = this.state;
list.forEach((item, k) => {
item.title = `Title ${k}`;
});
this.setState({list});
}
render(){
var { list } = this.state;
return (
<div>
<button onClick={this.updateTitles}>Update Title</button>
<ul>
{list.map((item, k) => (
<li onClick={() => this.updateTitle(k)} key={item.title}>{item.title}</li>
))}
</ul>
</div>
);
}
}
I can't get your question correctly. If you want to change value of title key of every child of list array just declare a function like this
function changeValue () {
let newList = this.state.list
newList.forEach(item => {
item.title = 'newTitle'
})
this.setState = ({
list: newList
})
}

Why aren't the props updating?

I am trying to add draggable attributes to a component that is rendered out, however, I don't know where to add them in exactly. So they at least render out but the array does no update on OnDragEnd when the item is dropped. The component:
const Item = props => {
const finishedButton = <button onClick={props.handleComplete} className="finishedButton">✔</button>
return (
<li className="background"
draggable
onDragStart={props.dragStart}
onDragEnd={props.dragEnd}
>
{finishedButton}{props.item}
</li>
and in the render in App
<ul onDragOver={e => this.dragOver(e)}>
{this.state.items.map((item, i)=> (
<Item
data-id={i}
key={i}
dragStart={e => this.dragStart(e)}
dragEnd={e => this.dragEnd(e)}
item={item.text}
/>
))}
</ul>
Codepen: https://codepen.io/Matt-dc/pen/zbYKNv
In your dragEnd function this.draggedElem is not defined. And therefore prevIndex & newIndex is undefined as well, which leads to data.splice returning the old state.
I am not sure about your logic, but seems it works
let placeholder = document.createElement("li");
placeholder.className = "placeholder";
const Item = props => {
const finishedButton = <button onClick={props.handleComplete} className="finishedButton">✔</button>
return (
<li className="background"
draggable
onDragStart={props.dragStart}
onDragEnd={props.dragEnd}
onDragOver={props.dragOver}
>
{finishedButton}{props.item}
>
</li>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{id: 1, text: "clean car", complete: false},
{id: 2, text: "wash dog", complete: false},
{id: 3, text: "water plants", complete: false},
{id: 4, text: "prune shrubs", complete: false},
{id: 5, text: "tidy house", complete: false}
],
input: ""
}
this.dragStart = this.dragStart.bind(this);
this.dragOver = this.dragOver.bind(this);
this.dragEnd = this.dragEnd.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = e => {
this.setState({
input: e.target.value
});
}
handleSubmit = () => {
let newItem = {};
newItem.id = uuid.v4();
newItem.text = this.state.input;
newItem.complete = false;
let newItems = this.state.items.concat(newItem);
this.setState({
items: newItems,
});
this.setState({input: ''})
}
handleComplete = e => {
}
dragStart = e => {
this.draggedElem = e.target;
e.dataTransfer.setData('text/html', this.draggedElem);
}
dragOver = e => {
e.preventDefault();
//this.draggedElem.style.display = "none";
if(e.target.className === 'placeholder') return;
this.newIndex = e.target
}
dragOverItem = (id,e) => {
this.to = id;
}
dragEnd = (from,e) => {
let data = this.state.items;
let prevIndex = from;
let newIndex = this.to;
console.log(`from ${prevIndex} to ${newIndex}`)
//if(prevIndex < newIndex) newIndex --;
data.splice(newIndex, 0, data.splice(prevIndex, 1)[0]);
this.setState({ items: data });
}
render() {
return(
<div>
<input onChange={this.handleChange} value={this.state.input} />
<button onClick={this.handleSubmit}>Add item</button>
<ul onDragOver={this.dragOver}>
{this.state.items.map((item, i)=> (
<Item
data-id={i}
key={i}
dragOver={this.dragOverItem.bind(this,i)}
dragStart={e => this.dragStart(e)}
dragEnd={this.dragEnd.bind(this, i)}
item={item.text}
/>
))}
</ul>
<p>{this.state.input}</p>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));

ReactJS won't print an array in the order that it is stored?

I have an issue with my reactjs code where the render() function won't print an array in the order that it is stored in my state object.
Here's my code which is pretty simple:
import React from "react";
export default class DonationDetail extends React.Component {
constructor(props) {
super(props);
this.state = { content: [] };
}
componentDidMount() {
let state = this.state;
state.content.push({ food: "burger" });
state.content.push({ food: "pizza" });
state.content.push({ food: "tacos" });
this.setState(state);
}
addPaymentItem() {
const item = { food: "" };
let state = this.state;
state.content.unshift(item);
this.setState(state);
}
render() {
console.log(this.state);
let ui = (
<div>
<button type="button" onClick={() => this.addPaymentItem()}>
add to top
</button>
{this.state.content.map((item, key) => (
<input type="text" key={key} defaultValue={item.food} />
))}
</div>
);
return ui;
}
}
When you press the button add to top, a new item is placed to the front of the state.content array, which you can verify from the console.log(this.state) statement. But what's unusual is that the HTML that is generated does NOT add this new item to the top of the user interface output. Instead, another input field with the word taco is placed at the bottom of the list in the user interface.
Why won't ReactJS print my state.content array in the order that it is actually stored?
You can use the array index as key when the order of the elements in the array will not change, but when you add an element to the beginning of the array the order is changed.
You could add a unique id to all your foods and use that as key instead.
Example
class DonationDetail extends React.Component {
state = { content: [] };
componentDidMount() {
const content = [];
content.push({ id: 1, food: "burger" });
content.push({ id: 2, food: "pizza" });
content.push({ id: 3, food: "tacos" });
this.setState({ content });
}
addPaymentItem = () => {
const item = { id: Math.random(), food: "" };
this.setState(prevState => ({ content: [item, ...prevState.content] }));
};
handleChange = (event, index) => {
const { value } = event.target;
this.setState(prevState => {
const content = [...prevState.content];
content[index] = { ...content[index], food: value };
return { content };
});
};
render() {
return (
<div>
<button type="button" onClick={this.addPaymentItem}>
add to top
</button>
{this.state.content.map((item, index) => (
<input
type="text"
key={item.id}
value={item.food}
onChange={event => this.handleChange(event, index)}
/>
))}
</div>
);
}
}
ReactDOM.render(<DonationDetail />, document.getElementById("root"));
<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="root"></div>
Instead of:
componentDidMount() {
let state = this.state;
state.content.push({ food: "burger" });
state.content.push({ food: "pizza" });
state.content.push({ food: "tacos" });
this.setState(state);
}
Try
componentDidMount() {
this.setState(prevState => ({
content: [
...prevState.content,
{ food: "burger" },
{ food: "pizza" },
{ food: "tacos" },
]
}));
}
and
addPaymentItem() {
const item = { food: "" };
let state = this.state;
state.content.unshift(item);
this.setState(state);
}
to
addPaymentItem() {
this.setState(prevState => ({
content: [
{ food: "" },
...prevState.content,
]
}));
}

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

Resources