How to push new column into array using setState - javascript

I am using an external library to build a Taskboard and what I want to achieve is to add a new column when clicking and add column button. I am struggling with adding the column, I have the newly created column but it doesn't get added to the array. What am I doing wrong and how can I insert the newly created column? Here is my code:
onAddColumn = () => {
const newColumn: TaskBoardColumnModel = {
id: this.state.columnsData.length + 1,
title: 'New Column',
status: 'new',
edit: true,
};
console.log(this.state.columnsData);
this.setState({
columsData: newColumn,
});
console.log(this.state.columsData);
};
}

Your main issue is the way you update your state. This is what you have:
this.setState({
columsData: newColumn,
});
This piece of code will set the state to columsData: newColumn, which is wrong for a few reasons:
columsData should be columnsData
Your piece of code will remove all the other columns and replace it with only one. Which will fail the code because columnsData will become an object and not an array
Here is what it should be:
this.setState({
columnsData: [...this.state.columnsData, newColumn],
});
This will keep your current state, and add the new column to your existing list.

You have a typo in columsData. Additionally columnsData should be an array so you probably need to set the new state to the old one plus the new column.
e.g. something like:
this.setState({
columnsData: [...this.state.columnsData, newColumn],
});

this.setState({
if(this.state.columnsData && this.state.columnsData.length>0)
{
columnsData: [...this.state.columnsData, newColumn],
}
});

Related

ReactJS Complex Form Input Field Duplicating Text in Multiple Input Fields

I have a form where you can add/remove groups and input items, I was able to get the groups of input field working, but I'm having trouble with the items input within the respected groups:
I created a code sand box here: https://codesandbox.io/s/twilight-cache-4ipv6?file=/src/Form.jsx
If you click on Add Items + button, and type in the item fields, the value duplicates to all the fields.
Also, sometimes I feel like the x button doesn't work, and will only remove the last item or something, I believe this is "controlled component?"
In addition, I want to ask if there's a better method on what I'm doing? It seems like there's a lot of complexities in the code I'm trying to write up. I feel like I'm writing too much of the set state hooks.
I think we don't need that fields state.
And we can update Add Handlers like this
const handleAddGroup = i => {
const newGroup = [...group];
newGroup.push({
id: null,
cat: "",
items: [
{
name: "",
value: ""
}
]
});
setGroups(newGroup);
};
const handleAddField = i => {
setGroups(state => {
const stateCopy = JSON.parse(JSON.stringify(state));
stateCopy[i].items.push({
name: "",
value: ""
});
return stateCopy;
});
};
https://codesandbox.io/s/cool-frog-2yrlt

JavaScript in Vue Component, set Data property in object 1 tp data in object 2 if Key matches

I think I'm close to a solution but I need some help,
I have a form object I want to update where key's match to an imported object.
form.title would be set to the value in article.title.
I have done the following, but am struggling how to set this.form[key][value] to this.article[articleKey][articleValue].
Object.entries(this.form).forEach(([key, value]) => {
Object.entries(this.article).forEach(([articleKey, articleValue]) => {
if ([articleKey][0] === [key][0]){
//[value] = [articleValue];
//this.form[key][value]=this.article[articleKey][articleValue]
}
});
Any help would be appreciated, i'm new to javascript. I can't clone the object as i only want to update the data properties in form and bring across all the data in article object.
Response to comment - example of form
form: new Form({
title: '',
description: '',
earliest_date:'',
latest_date:'',
image_file_names:[]
})
Article Example
{"id":21,
"owner_id":1,
"title":"test1",
"description":"Test It",
"earliest_date":"2020-06-01",
"latest_date":"2020-06-06",
"image_file_names":"[\"1593530083background.jpg\",
\"159353008520190713_085629.jpg\"]",
"physical_description":"Test 1"}
This looks to be working, it felt wrong setting value to the key but its not doing that, it is setting value of that key.
Object.entries(this.form).forEach(([key, value]) => {
Object.entries(this.article).forEach(([articleKey, articleValue]) => {
if ([articleKey][0] === [key][0]){
this.form[key] = [articleValue];
}
});
});

How to add dynamic input values to the local state for retrieval

I have a React Native form that allows me to add an Input UI in the form, by clicking a button with this function. This allow me to generate it on the fly. The code for that is this.
addClick() {
this.setState(prevState => ({ values: [...prevState.values, ""] }));
console.log(this.values[0].name);
}
That part works well, but I'm having a problem extracting the data from the dynamic inputs, and add it to an array. So far I have tried this
setVal = value => {
const values = this.state.values[0];
if (values[0].name === "" || values[0].description === "") return;
[...this.state.values, value];
this.setState(values);
console.log(values);
};
How do I organize my states properly so that I can add as many inputs I need, and when I'm finished, I can update the state, and access the new data in my list component?
How do I update my state to the new Array? at the moment, this.state only shows the initial state set at the top.
I'm missing a few things
Please take a look at the full code sandbox HERE so you can see:
See...your created isssue is not so obvious we need to see where you call setVal() function but....
i think you will be more comfortable if you render your <input/> s directly from your state array, not from const x = [] variant. because it seems like you want a dynamic view and in such a cases you will need to bind your loop quantity from state. so:
this.state = {
x: [0,1,2,3,4]
}
and inside your render :
{this.state.x.map(x => {
return (
<TextInput
placeholder={`name${x}`}
value={values[x.toString()]}
handleBlur={() => handleBlur(x.toString())}
onChangeText={handleChange(x.toString())}
style={styles.input}
/>
);
})}

How to check/uncheck individual checkbox in react-native Table component

I am working on sample application. In that I used the table component to push the row, col values into an empty array. If the row, col values exist in empty array it has to show the check mark and if user clicks(or) selects the checked one again it has to uncheck. Can anyone please suggest me how to resolve this issue? Any best solutions are appreciated.
_showData = (data,i,j) => {
this.setState({iValue:i,jValue:j},()=>{
//this.fetchData()
this.state.tableCellData.push({"i":i,"j":j})
this.setState({isSelected:true,tableCellData:this.state.tableCellData},()=>{/*alert("array:"+JSON.stringify(this.state.tableCellData))*/})
if(this.state.isSelected == true){
this.setState({isSelected:false})
}else{
this.setState({isSelected:true})
}
this.state.tableCellData.map((item, index) => {
if(item.i == i && item.j == j){
this.state.tableCellData.splice(index,0)
this.setState({isSelected:false})
alert("splice:"+JSON.stringify(this.state.tableCellData))
}
})
this.fetchData()
})
}
I used this _showdata function to show clickable action on each cell data
Try to avoid mutating the state. This is how you can add an item to the state without mutating it:
this.setState({
isSelected:true,
tableCellData: [
...this.state.tableCellData,
{i, j}
]
});
Notice that I didn't push the new data directly to the tableCellData array (which would be a state mutation), but instead I created a new tableCellData array. I then updated the state using the new array. There's a good reason for this.
If you mutate the state (like in the code you posted), then oldState.tableCellData === newState.tableCellData (they both point to the same object in memory).

Why do I lose the current object state when 'this.props.actions.updateComment(event.target.value)' is called?

I trying trying to achieve the following: There is a textfield and once a user enters in a text, an object is created with the text assigned to a state property called 'commentText' which is located inside the 'comments' array which is inside the object (todo[0]) of 'todos' array. 'commentInput' is just a temporary storage for the input entered in the textfield, to be assigned to the 'commentText' of 'todo[0]' object's 'comments' array.
I retrieve the current state object via following:
const mapStateToProps=(state, ownProps)=>({
todo:state.todos.filter(todo=>todo.id==ownProps.params.id)
});
and dispatch and actions via:
function mapDispatchToProps(dispatch){
return{
actions: bindActionCreators(actions, dispatch)
}
So the retrieved object 'todo' has an array property named comments. I have a text field that has:
onChange={this.handleCommentChange.bind(this)}
which does:
handleCommentChange(event){
this.props.actions.updateComment(event.target.value)
}
Before handleCommentChange is called, the object 'todo[0]' is first fetched correctly:
But as soon as a text is inputted into the text field, onChange={this.handleCommentChange.bind(this)} is called and all of a sudden, 'todo[0]' state is all lost (as shown in the 'next state' log):
What may be the issue? Tried solving it for hours and hours but still stuck. Any guidance or insight would be greatly appreciated. Thank you in advance.
EDIT **:
{
this.props.newCommentsArray.map((comment) => {
return <Comment key={comment.id} comment={comment} actions={this.props.actions}/>
})
}
EDIT 2 **
case 'ADD_COMMENT':
return todos.map(function(todo){
//Find the current object to apply the action to
if(todo.id === action.id){
//Create a new array, with newly assigned object
return var newComments = todo.comments.concat({
id: action.id,
commentTxt: action.commentTxt
})
}
//Otherwise return the original array
return todo.comments
})
I would suspect that your reducer is not correctly updating the todo entry. It's probably replacing the contents of the entry entirely, rather than merging the incoming value in in some fashion.
edit:
Yup, after seeing your full code, your reducer is very much at fault. Here's the current code:
case 'ADD_COMMENT':
return todos.map(function(todo){
if(todo.id === action.id){
return todo.comments = [{
id: action.id,
commentTxt: action.commentTxt
}, ...todo.comments]
}
})
map() should be returning one item for every item in the array. Instead, you're only returning something if the ID matches, and even then, you're actually assigning to todo.comments (causing direct mutation) and returning the result of that statement (which might be undefined?).
You need something like this instead (which could be written shorter, but I've deliberately written it out long-form to clarify what's happening):
case 'ADD_COMMENT':
return todos.map(function(todo) {
if(todo.id !== action.id) {
// if the ID doesn't match, just return the existing objecct
return todo;
}
// Otherwise, we need to return an updated value:
// Create a new comments array with the new comment at the end. concat() will
// You could also do something like [newComment].concat(todo.comments) to produce
// a new array with the new comment first depending on how you want it ordered.
var newComments = todo.comments.concat({
id : action.id,
commentTxt : action.commentTxt
});
// Create a new todo object that is a copy of the original,
// but with a new value in the "comments" field
var newTodo = Object.assign({}, todo, {comments : newComments});
// Now return that instead
return newTodo;
});

Categories