How can I manipulate a 2D array in React? - arrays

i tried to save list of equipments in arrays.
i need to add quantity for each equipemnt so i have to transform the one dimensional to two dimensional
how can i change this todeclare in state arrays as 2D?
this.state = {
equipments: [{
number: ''
},{
number: ''
}]};
and how to setsate ?
handleSubmit(event) {
const orderData = {
equipments: this.state.equipments.map(equipment => {
return {equipemnt: equipment.number}
})
};
createOrder(orderData);
}
validateEquipment = (equipmentNumber) => {
if(equipmentNumber.length === 0) {
return {
validateStatus: 'error',
errorMsg: 'Please enter a choice!'
}
} else if (equipmentNumber.length > 50) {
return {
validateStatus: 'error',
errorMsg: `Choice is too long (Maximum 50 characters allowed)`
}
} else {
return {
validateStatus: 'success',
errorMsg: null
}
}
}
handleEquipmentChange(event, index) {
const equipments = this.state.equipments.slice();
const value = event.target.value;
equipments[index] = {
number: value,
...this.validateEquipment(value)
}
this.setState({
equipments: equipments
});
}

it would be easier if you use object instead of array
this.state = {
equipments: {
eq1: { qty: 0 },
eq2: { qty: 0 }
}
}
adding / updating new equipment would be as simple as:
addOrUpdateQty(id, qty) {
this.setState({ equipments: {...this.state.equipments, [id]: { qty }} })
}

Related

this.setState isn't making changes in state

I am using functions that change a value in a nested object in the state :
an I am calling those functions in a button , they are executed when I click on that button , but one of those functions doesn't make changes to the state
This is the state :
state = {
data: {
attributesLength: this.props.product.attributes.length,
modalMessage: "",
isOpen: false,
},
};
and these are the functions :
addToCart = (id) => {
let data = { ...this.state.data };
if (Object.keys(this.state).length === 1) {
data.modalMessage = "Please, select product attributes";
this.setState({ data});
return;
}
if (
Object.keys(this.state).length - 1 ===
this.state.data.attributesLength
) {
const attributes = Object.entries(this.state).filter(
([key, value]) => key !== "data"
);
if (this.props.cartProducts.length === 0) {
this.props.addItem({
id: id,
quantity: 1,
attributes: Object.fromEntries(attributes),
});
data.modalMessage = "Added to cart !";
this.setState({ data });
return;
}
const product = this.props.cartProducts.filter((item) => item.id === id);
if (product.length === 0) {
this.props.addItem({
id: id,
quantity: 1,
attributes: Object.fromEntries(attributes),
});
data.modalMessage = "Added to cart !";
this.setState({ data });
return;
}
if (product.length !== 0) {
this.props.changeQuantity({ id: id, case: "increase" });
data.modalMessage = "Quantity increased !";
this.setState({ data });
return;
}
if (this.state.data.attributesLength === 0) {
this.props.addItem({
id: id,
quantity: 1,
attributes: Object.fromEntries(attributes),
});
data.modalMessage = "Added to cart !";
this.setState({ data });
return;
}
} else {
data.modalMessage = 'please, select "ALL" product attributes!';
this.setState({ data });
}
};
changeModalBoolean = () => {
let data = { ...this.state.data };
data.isOpen = !data.isOpen;
this.setState({ data });
};
and this is where I am calling functions :
<button
className={product.inStock ? null : "disabled"}
disabled={product.inStock ? false : true}
onClick={() => {
this.addToCart(product.id);
this.changeModalBoolean();
}}
>
{product.inStock ? "add to cart" : "out of stock"}
</button>
NOTE
changeModalBoolean function works and change state isOpen value,
this.addToCart(product.id);
this.changeModalBoolean();
This code run synchronously one after the other. In every function, you create a copy of previous state let data = { ...this.state.data };
so the this.changeModalBoolean(); just replace state which you set in this.addToCart(product.id); to fix this problem, use this.setState((state) => /*modify state*/)
changeModalBoolean = () => {
this.setState((state) => {
let data = { ...state.data };
data.isOpen = !data.isOpen;
return { data };
})
};
or modify the same object in both functions

Chartjs populate data with Axios response

I am attempting to have the data on the chart populate based on the set of data the user selects i.e past 24-hours, past week, etc. I am saving the data and the labels in state. The labels update according to the selected time frame, but none of the data populates. I have console logged the data (this.state.data.datasets[0].data[0]) and it is the correct data.
Here is my code:
class ChartDemo extends Component {
state = {
target: 20,
timeFrame: "past-hours",
totalSales: [],
data: {
labels: [],
datasets: [
{
label: "",
backgroundColor: "",
// data results
data: []
}
]
},
chartIsLoaded: false,
}
getData = (start, end) => {
API.getData(start, end)
.then(res =>
this.setState(state => {
// if any sales have occured in selected time period
if (res.data[0] !== undefined) {
let total = res.data[0].profit.toFixed(2);
let totalString = total.toString();
const totalSales = state.totalSales.concat(totalString);
return {
totalSales
};
} else {
// set to zero if no sales
const noSale = "0.00";
const totalSales = state.totalSales.concat(noSale);
return {
totalSales
};
}
})
)
.catch(error => console.log( error));
}
UNSAFE_componentWillMount() {
this.setTimeFrame();
}
setTimeFrame() {
const day-one = 2019-08-01;
const day-two = 2019-08-02;
const timeFrame = this.state.timeFrame;
this.setState({ target: 20 });
if (timeFrame === "past-hours") {
this.getData(day-one, day-two);
if (this.state.totalSales.length < 8) {
this.setState({ target: 7, chartIsLoaded: true });
setTimeout(
function () {
this.setState(prevState => ({
data: {
...prevState.data,
labels: [
timeset-one,
timeset-two,
timeset-three,
timeset-four,
timeset-five,
timeset-six,
timeset-seven,
timeset-eight,
],
datasets: [{
...prevState.data.datasets,
label: "24-hour Profit in $",
backgroundColor: "rgb(1,41,95)",
data: [this.state.totalSales]
}]
}
}))
}.bind(this), 1000
)
}
}
}
I solved this by removed the [] around this.state.totalSales. I was essentially putting an array into another array.

What is the best way to update object array value in React

My React state:
//...
this.state = {
mylist: [
{
"id": 0,
"trueorfalse": false
},
{
"id": 1,
"trueorfalse": false
}
]
}
//...
I am trying to update the trueorfalse value based on the id
Here is what I did so far but didn't work:
var idnum = e.target.id.toString().split("_")[1] //getting the id via an element id (0 or 1 in this case)
var TorF = true
if (type === 1) {
this.setState({
mylist: this.state.mylist.map(el => (el.id === idnum ? Object.assign({}, el, { TorF }) : el))
})
}
I really want to make it dynamic so the trueorfase will be opposite of what it is now:
var idnum = e.target.id.toString().split("_")[1] //getting the id via an element id (0 or 1 in this case)
if (type === 1) {
this.setState({
mylist: this.state.mylist.map(el => (el.id === idnum ? Object.assign({}, el, { /* if already true set to false or vice versa */ }) : el))
})
}
How can I update my code to have the dynamicity shown in the second example (if possible), otherwise the first example would do just fine
Another solution using map:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
mylist: [
{
id: 0,
trueorfalse: false
},
{
id: 1,
trueorfalse: true
}
]
};
}
toggleBoolean = () => {
const ID = Number(this.state.selectedID);
this.setState(prevState => ({
mylist: prevState.mylist.map(item => {
if (item.id === ID) {
return { ...item, trueorfalse: !item.trueorfalse };
} else {
return item;
}
})
}));
};
render() {
return (
<div className="App">
<p>{`State values: ${JSON.stringify(this.state.mylist)}`}</p>
<button onClick={this.toggleBoolean}>Change true/false values</button>
<label>Insert ID:</label>
<input
type="number"
onChange={event => this.setState({ selectedID: event.target.value })}
/>
</div>
);
}
}
I think the following code would accomplish your second question.
var idnum = e.target.id.toString().split("_")[1]
let newList = Array.from(this.state.mylist) //create new array so we don't modify state directly
if (type === 1) {
let objToUpdate = newList.find((el) => el.id === idnum) // grab first element with matching id
objToUpdate.trueorfalse = !objToUpdate.trueorfalse
this.setState( { mylist: newList } )
}

Find match in two arrays

Update
Got the answer:
if (this.checkedColors.length > 0) {
straps = straps.filter(strap => {
return strap.colors.find(color => {
return this.checkedColors.includes(color.title.toLowerCase());
});
});
}
I have two arrays, where I need to return products that match the checkbox value.
I've created a screen recording to display how this works: http://recordit.co/EddLjeqM7i
My code is the following:
export default {
data() {
checkedColors: [],
filterings: [{
title: "Farver",
filters: [{
title: "Grøn",
value: "grøn"
},
{
title: "Rød",
value: "rød"
},
{
title: "Gul",
value: "yellow"
},
{
title: "Lilla",
value: "lilla"
},
{
title: "Blå",
value: "blå"
},
{
title: "Grå",
value: "grå"
},
{
title: "Sort",
value: "sort"
},
{
title: "Hvid",
value: "hvid"
},
{
title: "Brun",
value: "brun"
}
]
}
}
},
computed: {
filteredStraps() {
var straps = this.straps;
if (this.search !== null) {
var straps = this.searchItems.filter(strap => {
if (!this.search) return this.searchItems;
return (
strap.title.toLowerCase().includes(this.search.toLowerCase()) ||
strap.skin.toLowerCase().includes(this.search.toLowerCase()) ||
strap.type.toLowerCase().includes(this.search.toLowerCase())
);
});
}
if (this.checkedSkins.length > 0) {
straps = straps.filter(strap => {
return this.checkedSkins.includes(strap.skin.toLowerCase());
});
}
if (this.checkedTypes.length > 0) {
straps = straps.filter(strap => {
return this.checkedTypes.includes(strap.type.toLowerCase());
});
}
if (this.checkedColors.length > 0) {
straps = straps.filter(strap => {
return this.checkedColors.includes(strap.colors.toLowerCase());
});
}
if (this.sort == "newest") {
return straps.sort((a, b) => new Date(a.date) - new Date(b.date));
}
if (this.sort == "priceasc") {
return straps.sort((a, b) => a.price > b.price);
}
if (this.sort == "pricedesc") {
return straps.sort((a, b) => a.price < b.price);
} else {
return straps;
}
}
},
<v-expansion-panel class="elevation-0">
<v-expansion-panel-content v-for="filtering in filterings.slice(0, 1)" :key="filtering.title">
<div slot="header">{{filtering.title | capitalize}}</div>
<v-card>
<v-card-text>
<v-list>
<v-list-tile v-for="filter in filtering.filters" :key="filter.value">
<v-list-tile-content>
<v-checkbox :value="filter.value" :label="filter.title" v-model="checkedColors" color="primary"></v-checkbox>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
The straps array is the following: https://i.imgur.com/HIEBgqW.png
I'll need the function to be computed in order to match the other filtering and sorting methods, to return the straps correctly.
I have two other methods that are working, but they didn't require looping through an array to find a match for the value or values I'm looking for.

Filter out existing objects in an array of objects

I don't think this is difficult, I just can't figure out the best way to do it. This function is creating an array, from a group of checkboxes. I then want to break up the array and create an array of objects, because each object can have corresponding data. How do I filter out existing rolesInterestedIn.roleType.
handleTypeOfWorkSelection(event) {
const newSelection = event.target.value;
let newSelectionArray;
if(this.state.typeOfWork.indexOf(newSelection) > -1) {
newSelectionArray = this.state.typeOfWork.filter(s => s !== newSelection)
} else {
newSelectionArray = [...this.state.typeOfWork, newSelection];
}
this.setState({ typeOfWork: newSelectionArray }, function() {
this.state.typeOfWork.map((type) => {
this.setState({
rolesInterestedIn: this.state.rolesInterestedIn.concat([
{
roleType: type,
}
])
}, function() {
console.log(this.state.rolesInterestedIn);
});
})
});
}
UDPATE
rolesInterestedIn: [
{
roleType: '',
experienceYears: ''
}
],
Because each time you do setState you are concatenating the new value to the prev one in rolesInterestedIn array. Add new value only when you are adding new item, otherwise remove the object from both the state variable typeOfWork and rolesInterestedIn.
Try this:
handleTypeOfWorkSelection(event) {
const newSelection = event.target.value;
let newSelectionArray, rolesInterestedIn = this.state.rolesInterestedIn.slice(0);
if(this.state.typeOfWork.indexOf(newSelection) > -1) {
newSelectionArray = this.state.typeOfWork.filter(s => s !== newSelection);
rolesInterestedIn = rolesInterestedIn.filter(s => s.roleType !== newSelection)
} else {
newSelectionArray = [...this.state.typeOfWork, newSelection];
rolesInterestedIn = newSelectionArray.map((workType) => {
return {
roleType: workType,
experienceYears: '',
}
});
}
this.setState({
typeOfWork: newSelectionArray,
rolesInterestedIn: rolesInterestedIn
});
}
Suggestion: Don't use multiple setState within a function, do all the calculation then use setState once to update all the values in the last.

Resources