I am trying do loop over a prop and push the parent and child to a variable. I seem to be able to get the looping and pushing working correctly, but its pushing all the children under each parent
var options = [];
var option = [];
Object.keys(this.props.data.options).forEach((key, index) => {
options.push(
<AddToCartRow key={index} option={key} options={option} cartKey={this.props.cartKey} />,
Object.values(this.props.data.options[key]).forEach((value, index) => {
option.push(value)
})
)
})
Below is what is currently happening
The expected result should be
size
- 0[price: 3.95, title: Small]
- 1 [price: 4.95, title: Large]
blend
- 0[price: 0, title: Regular]
- 1 [price: 0, title: Decaf]
etc
It seems you have problem with pushing element into array. I have managed by doing as below
for (let parentData of mainObj) {
let tempArray = []; // need to declare here
for (let childData of parentData.someField) {
tempArray.push({
...
});
}
finalArray.push(tempArray);
}
You need to push your child loop data into temporary array and then to main resultant array which is options in your case .
Related
Even replicating the object succeeded. However, the id value is duplicated the same. Therefore, if you click the delete button, the deletion will be done together.But I want to get a different ID. How can I fix it here?
const handleduplicate = id => {
const dupDataGroup = [...Groupdata].filter(item => item.id === id);
const newGroup = [dupDataGroup[0], ...Groupdata];
setGroupData(newGroup);
};
The result when I didn't do anything =>
0: {id: 0, title: 'blur', subtitle: 'Img'}
1: {id: 1, title: 'blurs', subtitle: 'Ima'}
2: {id: 2, title: 'Free ', subtitle: 'Ima'}
handleduplicate click result=>
0: {**id: 0**, title: 'blur', subtitle: 'Img'}
1: {**id: 0,** title: 'blur', subtitle: 'Img'}
2: {id: 1, title: 'blurs', subtitle: 'Ima'}
3: {id: 2, title: 'Free ', subtitle: 'Ima'}
I hope that only the ID value will change when duplicated.
React does not automatically update the key index in JSON objects. Also, in this scenario, you're fetching the value and inserting it into the newGroup.
If you really want to update the keys, I'd suggest creating a for loop to update the values of id.
const handleduplicate = id => {
const dupDataGroup = [...Groupdata].filter(item => item.id === id);
const newGroup = [dupDataGroup[0], ...Groupdata];
for (var i = 0; i < newGroup.length; i++)
newGroup[i].id = i;
setGroupData(newGroup);
};
You can duplicate an object by using the spread operator.
const obj = {name: 'ritik', surname: 'banger'};
const objCopy = {...obj};
or use of Object.assign will work for you.
let objcopy = Object.assign({}, obj);
You must note that here we are referencing the original object 'obj' and thus any changes in 'objcopy' will reflect in 'obj', this is known as shallow copy.
If you want to deep copy the object and you wish to have different reference for both then,
Using JQuery library:
import jQ from "jquery";
let objcopy = jQ.extend(true, obj, {});
Using lodash library:
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
[...Groupdata] creates a new list with the (non-duplicated) items in Groupdata. This is important if you'd want to add the item twice to the list, as changing one with change the same object as you already noticed. You will also have to duplicate the item itself.
Note that duplicating the list itself isn't necessary if you're just going to filter on it.
What I also think is happening, given the additional information in the comments, is that setGroupData is used multiple times. If you use Groupdata, followed by setGroupData, then Groupdata is not updated accordingly. So just make sure you use that function once.
const handleduplicate = (groupData, id, newId) => {
const dupDataGroup = groupData.filter(item => item.id === id); // no copying here.
const rest = groupData.filter(item => item.id !== id);
const newGroup = [
{ // the item is duplicated (note: no deep copy)
...dupDataGroup[0],
id: newId // updated with the new identifier
},
...rest
];
return newGroup;
};
const duplicated = handleduplicate(Groupdata, 123, 456);
setGroupData(duplicated);
In my state I have an object called foodLog which holds all entries a user enters with one of the keys being foodSelectedKey and I'm trying to return all entries that have a matching value from that key with a different array called foodFilter.
However, this doesn't work and errors out saying foodLog.filter() isn't a function - I've looked this up and it's because it's an Object (I think). Any help would be greatly appreciated!
state = {
// log food is for the logged entries
foodLog: {},
// used for when filtering food entries
foodFilter: [],
};
findMatches = () => {
let foodLog = this.state.foodLog;
let foodFilter = this.state.foodFilter;
let matched = foodLog.filter((item) => {
return foodLog.foodsSelectedKey.map((food) => {
return foodFilter.includes(food);
});
});
};
I guess the reason behind the error Is not a function is that the object can not be looped. By that it means you can not iterate an object with differend variables inside, if it has no index to be iterated like an array. The same goes for map(), find() and similar functions which MUST be run with arrays - not objects.
As far as I understand you have an object named foodLog which has an array named foodsSelectedKey. We need to find intersected elements out of foodFilter with the array. This is what I came up with:
state = {
// log food is for the logged entries
foodLog: {
foodsSelectedKey: [
{ id: 1, name: "chicken" },
{ id: 2, name: "mashroom" }
]
},
// used for when filtering food entries
foodFilter: [
{ id: 1, name: "chicken" },
{ id: 2, name: "orange" }
]
};
findMatches = () => {
let foodLog = this.state.foodLog;
let foodFilter = this.state.foodFilter;
let matched = foodLog.foodsSelectedKey.filter((key) =>
{
for (let i=0; i<foodFilter.length;i++){
if(foodFilter[i].name===key.name)
return true
}
return false;
}
);
return matched;
};
The Output is filtered array, in this case, of one element only:
[{
id: 1
name: "chicken"
}]
In order to check the output - run console.log(findMatches()). Here is the CodeSandbox of the solution. (check console at right bottom)
The newArray i create and push url's to, is not added properly to my state variable (propFiles)
const [propFiles, setPropFiles] = useState([]);
useEffect(() => {
let newArray = [...propFiles];
data?.forEach((element) => {
element?.images?.forEach((el) => {
storageRef
.child(element.firebaseRef + "/" + el)
.getDownloadURL()
.then((url) => {
console.log(url) // this returns url's like "https://firebase/my-picture.jpg"
newArray.push(url);
console.log(newArray) // this updates the array as expected so the result of newArray is ok
setPropFiles(...propFiles, newArray) // This is where something goes wrong
});
});
});
}, [data]);
useEffect(() => {
console.log(propFiles); // The complete array values (of newArray) are not transfered proper to state. Only the first 2 url's are
}, [propFiles]);
So after each console.log you can find my information about what is going on.
As you can see, if i try to log propFiles, it only shows me the to 2 first elements of the foreach loop, not the complete newArray that was made.
Can someone please explain to me what would be the right approach to set state equal to the complete newArray that was made?
UPDATE To be extra clear about the outcomes of newArray and propFiles
This is what newArray looks like after the foreach:
[
0: "https://firebase/my-picture-1.jpg",
1: "https://firebase/my-picture-2.jpg",
2: "https://firebase/my-picture-3.jpg",
3: "https://firebase/my-picture-4.jpg",
4: "https://firebase/my-picture-5.jpg",
5: "https://firebase/my-picture-6.jpg",
6: "https://firebase/my-picture-7.jpg",
7: "https://firebase/my-picture-8.jpg",
8: "https://firebase/my-picture-9.jpg",
9: "https://firebase/my-picture-10.jpg",
10: "https://firebase/my-picture-11.jpg",
11: "https://firebase/my-picture-12.jpg",
]
So an array with 11 url (or strings) inside of it
This is what propFiles look like after it is set equal to newArray:
[
0: "https://firebase/my-picture-1.jpg",
1: "https://firebase/my-picture-2.jpg"
]
So an array with just 2 urls (or strings) inside of it.
How could this be possible?
Thanks in advance
propFiles state is an array and hence you are updating it, you should set an array back but you are setting comma separated values
Correct way to update it would be
setPropFiles(newArray)
since you have already used the propFiles while initialising the newArray
However, another thing to note is that you are looping over elements and updating state, it is always better to get the final updated array and update it only once. The way to do it would be to map over the items and use Promise.all
const [propFiles, setPropFiles] = useState([]);
useEffect(() => {
const promises = data?.map((element) => {
return element?.images?.map((el) => {
return storageRef
.child(element.firebaseRef + "/" + el)
.getDownloadURL()
.then((url) => {
console.log(url) // this returns url's like "https://firebase/my-picture.jpg"
console.log(newArray) // this updates the array as expected so the result of newArray is ok
return url
});
});
}).filter(Boolean); // remove all undefined values
// flatten the promise array since we have nested maps
const promisesArr = promises?.flat();
promisesArr && Promise.all(promisesArr).then(newArray => {
setPropFiles(prevPropsFiles => [...prevPropsFiles, ...newArray])
})
}, [data]);
So I'm working with states in React, and i want to compare the two arrays/state and get the data from the first array that doesn't match with the data on the second array.
The first array is a state, and the second one is an array.
My first state/array looks like this = state : [ { id : id , productNumber : "productnumber"}... ] and the second array loos like this = array ["productnumber","productnumber"...],
and here what is my code's look like.
let newArray = [];
state.forEach(product=>{
array.forEach(productNumber=>{
if(product.productNumber !== productNumber){
newArray = [...newArray,product.productNumber];
}
})
})
and it doesn't work, it stores all the data from the first array/state and even doubled it. I tried using nested if statements, still doesn't. I don't know what todo.
let newArray = [];
state.forEach(({productNumber}) => {
if (array.indexOf(productNumber) === -1) {
newArray = [...newArray, productNumber];
}
})
Or similarly, you can filter the state array and return the products with productNumber not in your second array.
const newArray = state.filter(({productNumber}) => array.indexOf(productNumber) === -1);
I have the following JSON definition:
export class Company {
name: string;
trips : Trip[] = [];
}
I am able to see the trips in the console using:
console.log(this.company);
But I am not able to access the array elements (trip), I've tried
the following:
for(let i = 0; i < this.company.trips.length; i++){
console.log(this.company.trips[i]);
}
When I display the company to the log I'm getting the trip as you can
see below:
{id: 1}
name: "Sample"
trips: {id: 1, r: "ABC"}
id: 1
Any idea how to access array elements in Angular thanks?
Using a combination of Object.keys() and forEach() will let you iterate through the the object in a similar fashion to an array.
explination
const x = {hello: "hi"};
console.log(Object.keys(x)); // will return array looking like
// [hello] which you can run a for each on.
Object.keys(x).forEach(data => {
console.log(x[data]); // will return `hi`
});
Solution
const trips = {id: 1, r: "ABC"}; // const trips = this.company.trips
if (trips) // check the value exists here
{
Object.keys(trips).forEach((data) => {
console.log(trips[data]);
});
}
if(this.company)
this.Company.trips.forEach(x => {
console.log(x);
});