In a React project, I'm displaying certain records in a table which also has input text boxes for changing the values when needed. To process those changed records it needs to be added into an array, but, getting undefined when changed the values. Although each record is associated with unique id, unable to add in new array. Please refer to the code below.
const textChange = (data) => {
const { id, value } = data;
setDataNew((prevInfo) => {
// Here the records are getting undefined and not getting added into array
const dataIndex = id - 1;
prevInfo[dataIndex] = value;
return [...prevInfo];
});
};
Any suggestions and solution highly appreciated.
Please refer to code sandbox link for better clarity --> https://codesandbox.io/s/elated-varahamihira-xpjtdb?file=/src/Table.js:757-959
If I understood it correctly here is what you need to do if you need all the records which got updated :
const textChange = (data) => {
const { id, value } = data;
setDataNew((prevInfo) => {
const newList = [...prevInfo];
const index = newList.findIndex((datum) => datum.id === id);
if (index !== -1) {
newList[index] = { id, value };
} else {
newList.push({ id, value });
}
return [...newList];
});
};
Mistake in your code
You were getting undefined because you were calculating index like :
const dataIndex = id - 1;
if the changed object id was 6708 , you were adding element at 6707th index. Hence all first 6706 element were showing up as undefined.
Link : working demo
Related
In a table, certain input text fields are displayed. Accordingly data could be inputted in it. My intention is to club all the input data into an array. Each record has its specific unique id, which we get in console while we input in text box. Based on this id, I want to club into an array data. I've tried with one logic but gives error. Please have a look at the code below
// Here newData is an array of records which I'm displaying in Grid
const [dataNew, setDataNew] = useState(newData);
const textChange = (data) => {
const { id, value } = data;
setDataNew((prevInfo) => {
const dataIndex = +id[id.length - 1];
return {
...prevInfo,
// Here I'm getting error in the below code snippet in prevInfo
dataHere: Object.assign([...prevInfo.newData], { [dataIndex]: value })
};
});
};
console.log('NEW DATA', newData)
Please suggest me if any changes to be done. Any solution highly appreciated
Please refer codesandbox link --> https://codesandbox.io/s/elated-varahamihira-xpjtdb?file=/src/Table.js:149-197
dataNew is initially an array, but you are returning an object from the setDataNew callback.
Also id is a number itself in your sandbox, so the following would suffice:
const textChange = (data) => {
const { id, value } = data;
setDataNew((prevInfo) => {
const dataIndex = id - 1;
prevInfo[dataIndex] = value;
return [...prevInfo];
});
};
I have a problem with the getItem of my localStorage in my React Form. I put a onChange attribute:
<div className = 'InputForm' onChange={save_data}>
I found the setItem function to store the data in. Here is the function:
function save_data(){
let textarea = document.querySelectorAll("textarea")
let input = document.querySelectorAll("input[type='text']")
let saved_fields = []
textarea.forEach(x => {
saved_fields.push({
key: x.className,
value: x.value
})
})
input.forEach(x => {
saved_fields.push({
key: x.className,
value: x.value
})
})
localStorage.setItem("saved_data", JSON.stringify(saved_fields))
}
My main problem is that I don't find a way to put the data back to the page after the page reload. I just found out how to persist all my inputs in the console:
window.onload = dataLoad();
function dataLoad () {
let show_saved_data = localStorage.getItem("saved_data");
console.log('show_saved_data:',JSON.parse(show_saved_data));
}
Can you guys help me find the retrieve/persist data function?
Edit : Here is the html of the form, i use props from another component. I don't know if this can change the function i need to use.
<InputFields
stateKey = 'contactInfo'
key = {props.contactInfo.id}
completedFields = {props.contactInfo}
templateFields = {props.templates.contactInfo}
onDataEntry = {props.onDataEntry}
newField = {props.newField}
/>
Can we have your HTML form to help you? You should not identify your inputs / textareas by their className.
After that, by using ID as identifiers for your input / textarea, you just have to do it in reverse:
Get your input/textarea list
forEach items, set the value based on the ID
function dataLoad () {
var show_saved_data = localStorage.getItem("saved_data");
var inputList = JSON.parse(show_saved_data);
inputList.forEach(x => {
document.getElementById(x.key).setAttribute('value', x.value);
})
}
Giving us your complete HTML/JS will be easier to give you a complete solution.
I'm trying to add data from a single input field to an array which i want to store in localstorage but when i submit input button, the item is stored at first but if i try to store a second item, the array previous item is replaced with the newly typed item data instead of adding to it like i'd expect an array to behave. i don't understand this behaviour. i will really really appreciate a detailed explanation since i'm using react to do this.
This is my code below
input field
import React from "react";
import "./addoption.css";
function AddOption({ validateOption }) {
const handleAddoption = (e) => {
e.preventDefault();
const inputValue = e.target.elements[0].value.trim();
validateOption(inputValue);
e.target.elements[0].value = "";
};
return (
<div className="addoption">
<form onSubmit={handleAddoption}>
<input type="text" name="list" />
<button>Add Option</button>
</form>
</div>
);
}
export default AddOption;
*this is my code to add the input data to the localstorage *
const handleAddoption = (option) => {
if (!option) {
return setErrorhandler("Enter valid value to add item");
} else if (listItems.options.indexOf(option) > -1) {
return setErrorhandler("This option already exists!");
}
const array = localStorage.getItem("Options");
let items = [];
if (array) {
items = JSON.parse(array);
}
let storedArray = JSON.stringify(items.push(option));
localStorage.setItem("options", storedArray);
setListItems({ options: items });
};
``
Array.prototype.push certainly mutates the array, but it's return value isn't the array, it's the new length of the array. You may want to do the mutation separate from the JSON serializing.
The reason for the overwriting is because you're using two different storage keys for getting and setting. You are not getting what was stored so you are only appending new data to an empty array. Make sure you also use the same key to both retrieve and set the localStorage.
const handleAddoption = (option) => {
if (!option) {
return setErrorhandler("Enter valid value to add item");
} else if (listItems.options.indexOf(option) > -1) {
return setErrorhandler("This option already exists!");
}
const array = localStorage.getItem("options");
let items = [];
if (array) {
items = JSON.parse(array);
}
items.push(option);
localStorage.setItem("options", JSON.stringify(items));
setListItems({ options: items });
};
A more optimal solution would be to read in and initialize the options state from localStorage, and use an useEffect hook to just persist state updates back to localStorage. This way is a little easier to manage.
Example:
const initializeState = () => ({
// ... other listItems initial state
options: JSON.parse(localStorage.getItem("options")) || [],
});
const [listItems, setListItems] = useState(initializeState());
useEffect(() => {
localStorage.setItem("options", JSON.stringify(listItems.options));
}, [listItems.options]);
const handleAddoption = (option) => {
if (!option) {
return setErrorhandler("Enter valid value to add item");
} else if (listItems.options.indexOf(option) > -1) {
return setErrorhandler("This option already exists!");
}
setListItems(prevState => ({
...prevState
options: prevState.options.concat(option),
}));
};
Hi I'm working on a react project using Socket.io
On client side, it updates when an user click a different button with an Object such as
var actionArray, setActionArray
[actionArray, setActionArray] = React.useState({})
setActionArray({key: "rgb(211,40,21)", gesture: "🤘"})
As the user click a different button, only the gesture property changes.
On server side, several users will update their gesture simultaneously, and the color is used as key value to recognize different users. I want to accumulate the objects with different key in this 'colorArray' array, and update only the 'gesture' property when the user update their 'gesture' value with the same key property.
var colorArray = [];
socket.on("action", data => {
notifySubscribers(data);
console.log(data);
if (data.actionArray) {
colorArray.push({
key: data.actionArray.key,
id: id,
gesture: data.actionArray.gesture
});
subscribers.forEach(socket =>
socket.emit("colorArray", { colorArray: colorArray })
);
console.log(colorArray);
}
With the code above, it keeps adding new objects with same key value, but how can I update the object with same key with different 'gesture' property?
Here's some of the methods I tried, and didn't work.
//1
colorArray = colorArray.filter(item => item.key !== data.actionArray.key);
//2
let updatedItem = colorArray.find(element => {
return element.key === colorArray.key;
});
updatedItem.gesture = data.actionArray.gesture;
You were getting close, try this.
if (data.actionArray) {
let matchIndex = colorArray.findIndex(element => {
return element.key === data.actionArray.key
});
updatedItem = {
...data.actionArray,
id: id,
};
if (matchIndex > -1) {
colorArray[matchIndex] = updatedItem;
} else {
colorArray.push(updatedItem);
}
subscribers.forEach(socket =>
socket.emit("colorArray", { colorArray: colorArray })
);
console.log(colorArray);
}
i have an array in my component and based on the searchString i am filtering the array of items. and it is working fine.
if user removes the characters from the search field i want to show all the records again. but i am unable to show all records again when clearing the items from the search field.
please see below code.
this.filterServ.filterData.subscribe(searchData => {
if (Object.keys(searchData).length != 0) {
console.log('component', searchData);
this.cardData = this.cardData.filter((project) => {
let name = project.Name.toLowerCase();
if (name.includes(searchData.searchString.toLowerCase())) {
return true;
}
});
console.log('filterd data', this.cardData);
}
});
You already mutated the cardData. Therefore, you can't revert it back.
The solution is to create another property, for example you can name it displayData.
Then you can do like:
this.displayData = this.cardData.filter((project) => {
and instead of using cardData on the template, use displayData instead
Declare field filterData and bind this field in the template.
this.filterServ.filterData.subscribe(searchData => {
if (Object.keys(searchData).length != 0) {
console.log('component', searchData);
this.filterData= this.cardData.filter((project) => {
let name = project.Name.toLowerCase();
if (name.includes(searchData.searchString.toLowerCase())) {
return true;
}
});
console.log('filterd data', this.cardData);
}
});
Hope this help!
You should take copy of array data before filtering, and return the original array if input text is empty.
private originalData;
this.originalData = this.cardData.slice();
this.filterServ.filterData.subscribe(searchData => {
if (Object.keys(searchData).length != 0) {
console.log('component', searchData);
this.cardData = this.originalData.filter((project) => {
let name = project.Name.toLowerCase();
if (name.includes(searchData.searchString.toLowerCase()))
{
return true;
}
});
console.log('filterd data', this.cardData);
}
});