Modify object while passing through react component - javascript

I am trying to pass through an object that looks like this
{
"nodes": [
{
"attributes": null
},
{
"attributes": {
"nodes": [
{
"attributeId": 1,
"name": "pa_color",
"options": [
"gray"
]
},
{
"attributeId": 2,
"name": "pa_size",
"options": [
"large"
]
}
]
}
},
{
"attributes": {
"nodes": [
{
"attributeId": 1,
"name": "pa_color",
"options": [
"blue"
]
}
]
}
}
]
}
into a react component that renders all the different options under all the unique names. However, the way the data is structured means that I receive duplicates of names and options.
I am trying to convert the object into this object
{
"node": {
"attributeId": 1,
"name": "pa_color",
"values": [
{
"name": "gray"
},
{
"name": "blue"
}
]
},
"node": {
"attributeId": 2,
"name": "pa_size",
"values": [
{
"name": "large"
}
]
},
}
Current code looks like this
export interface Category_products_edges_node_attributes_edges_node {
__typename: "ProductAttribute";
/**
* Attribute Global ID
*/
name: string;
/**
* Attribute options
*/
options: (string | null)[] | null;
/**
* Attribute ID
*/
attributeId: number;
}
export interface ProductFiltersProps {
attributes: Category_products_edges_node_attributes_edges_node[]
}
export const ProductFilters: React.FC<ProductFiltersProps> = ({
attributes,
}) => (
<div className="product-filters">
<div className="container">
<div className="product-filters__grid">
{attributes.map(attribute => (
I have tried to do
{groupBy(attributes, 'attributeId').map(attribute => (
With the Lodash library, but receive the error
This expression is not callable. Type
'Category_products_edges_node_attributes_edges_node[]' has no call
signatures.
What is the best way to do this?
Thank you

lodash groupBy returns an Object not an Array therefore the javascript .map call will not work on it. Also groupBy is used to group items with similar property under one key inside an object, it isn't used to remove duplicates.
To remove duplicates use the lodash uniqBy method. This method can be called on an array and returns an array without duplicates.
Update:
To view in more detail how you can remove duplicates based on more than one property of object please see great answer
Also the output object you are trying to achieve has similar keys, I think that is not what you want, a Javascript object should not have duplicate keys. So my output gives keys as node0, node1 instead of node
You can achieve this as follows:
const nodes = {
nodes: [
{ attributes: null },
{
attributes: {
nodes: [
{ attributeId: 1, name: "pa_color", options: ["gray"] },
{ attributeId: 2, name: "pa_size", options: ["large"] }
]
}
},
{
attributes: {
nodes: [{ attributeId: 1, name: "pa_color", options: ["blue"] }]
}
}
]
}
const attributes = []
nodes.nodes.forEach(e => {
if (e.attributes && Array.isArray(e.attributes.nodes)) {
attributes.push(...e.attributes.nodes)
}
})
const uniqueAttributes = _.uniqBy(attributes, (obj) => [obj.attributeId, obj.name, obj.options].join())
const uniqueNodes = uniqueAttributes.map((e, i) => ({ ["node" + i]: e }))
console.log("Unique Nodes: ", uniqueNodes)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>

Related

TypeError: Cannot read properties of undefined (reading 'product-1')

So I am trying to display JSON data in my React.js project, but I am getting an error that I can't figure out. I've spent 2 days trying to figure it out, but had no luck
The JSON data: (filename: products.json)
{
"product-1": [
{
"id": 1,
"name": "product-1",
}
],
"product-2": [
{
"id": 2,
"name": "product-2",
}
],
"product-3": [
{
"id": 3,
"name": "product-3",
}
]
}
My javascript:
const productsData = Object.keys(backendData).map(key => {
return {
[key]: backendData[key]
}
})
console.log(productsData[0].products["product-1"][0].id)
error:
Log of backEndData:
Because productsData will return you array like this:
[
{ "product-1": [
{
"id": 1,
"name": "product-1",
}
]},
{"product-2": [
{
"id": 2,
"name": "product-2",
}
]}, ....
]
Meaning this is array of objects, where each object have one key-value pair, where key is name and value is an array.
If you want to access id then you should do like this:
productsData[0]["product-1"][0].id
UPDATED AFTER UPDATE OF OP
Since your backendData value does not match product.json, I will ignore that product.json and write you the solution which will work for the value of backendData you just provided.
const productsData = backendData.products;
const id = productsData[0]["product-1"][0].id;

Replace array in nested object in Javascript

I have spent a good part of the day trying to replace arrays of an existing nested object but I can't figure out how to do it. This is my original object:
{
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
text: 'Website questions',
items: Array(11)
}
]
},
{
"id": "79e42d88-7dd0-4f70-b6b4-dea4b4a64ef3",
"title": "Blogs",
"questions": [
...
]
},
{
"id": "439ded88-d7ed0-de70-b6b4-dea4b4a64e840",
"title": "App questions",
"questions": [
...
]
}
]
}
I would like replace the question arrays in the original object or in a copy of it.
const newMenu = [
{id: '34bb96c7-1eda-4f10-8acf-e6486296f4dd', text: 'Website questions', items: Array(24)},
{id: '520c2d3f-6117-4f6a-904f-2477e3347472', text: 'Blog questions', item: Array(7)},
{id: '302b658a-9d8c-4f53-80f6-3f2275bfble', title: 'App questions', items: Array(14)}
]
I am trying to do this by its index but unfortunately it doesn't work.
webSections.sections.forEach((item, index) => {
return webSections.sections[index].questions, newMenu[index]);
}
Does anyone see what am I doing wrong?
The value returned from the callback passed to forEach will not be used anywhere.
If you want to avoid mutating the original object and update questions, you can use Array.prototype.map and object spread syntax.
const object = {
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
...
const updatedObject = {
...object,
webSections: {
...object.webSections,
sections: object.webSections.sections.map((section, index) => ({...section, questions: newMenu[index]}))
}
}
If you just want to mutate the original object
object.webSections.sections.forEach((_, index) => {
section.questions = newMenu[index]
})
const newSections = myObj.webSections.sections.map((obj, index) => {
const newQuestions = newItems[index];
return {
...obj,
questions: [newQuestions],
};
});
console.log(newSections);
MyObj is the main object.
This shall produce the new sections array you can combine it with your main object I suppose...
#Ramesh Reddy has the most thorough answer.
The simplest way if you don't care about mutation is:
myObject.webSections.sections.forEach((section, index) => {
section.questions = newMenu[index].items;
})
You have used your 'forEach' with wrong syntax. Check MDN on how it's used.

Problem mapping over data from API as its just an object not an array of objects in React

If I have this data structure coming from an api:
{
"value": 0,
"time": [
"2021-10-15"
],
"innerArray": [
{
"name": "string",
"Value": [
0
]
}
]
}
I am trying to access the element by:
let dataLoop = data // object from api
then I am doing:
function Loop() {
dataLoop.map((inner: any) => {
console.log('series =', inner.innerArray);
})
};
But I am getting TypeError: dataLoop.map is not a function
It is because
{
"value": 0,
"time": [
"2021-10-15"
],
"innerArray": [
{
"name": "string",
"Value": [
0
]
}
]
}
is an object, you can map only on Array type elements.
innerArray is an element on which you can .map like this:
dataLoop.innerArray.map((inner: any) => {
console.log('series =', inner);
})
to be able to map through an object you have to use Object like:
Object.entries(data).map(([key,value])=>{
console.log(key,value)
})
for example, so output would be like :

unable to assign array to object attributes in javascript

Object attribute only hold the first element of the assigned value
let groupedDepActivities=[]
groupedDepActivities.push({
id:1,
term_activity:{
terms:[{id:1},{from:'here'},{to:'there'},]
}
})
the console.log() result will be
*
term_activity:
terms: Array(1)
0:
id: "1"
[[Prototype]]: Object
length: 1
*
terms attribute only hold the first element(id:1) of the array not all
The console's output may be truncated, but your code works as expected.
let groupedDepActivities = []
groupedDepActivities.push({
id: 1,
term_activity: {
terms: [{
id: 1
}, {
from: 'here'
}, {
to: 'there'
}, ]
}
})
console.log(groupedDepActivities);
Output:
[
{
"id": 1,
"term_activity": {
"terms": [
{
"id": 1
},
{
"from": "here"
},
{
"to": "there"
}
]
}
}
]
Were you wanting terms to be a single object?
let groupedDepActivities = []
groupedDepActivities.push({
id: 1,
term_activity: {
terms: {
id: 1,
from: 'here',
to: 'there',
}
}
})
console.log(groupedDepActivities);
[
{
"id": 1,
"term_activity": {
"terms": {
"id": 1,
"from": "here",
"to": "there"
}
}
}
]
you are only pushing one object, this one:
{
id:1,
term_activity:{
terms:[{id:1},{from:'here'},{to:'there'},]
}
}
Need to distiguish when you are handling an object: {}, from an array [].
To dive deeper in your data structure for example you can do:
console.log(groupedDepActivities=[0].term_activity.terms[0])
Maybe its also useful to wrap your item to log in braces, as it appears as an object with names in the console, like this:
console.log({groupedDepActivities})
In case checking the names of the variables you log while you unfold them to check what do they hold make you more compfortable :)

Remove duplicate nested objects in array using Lodash

I have an array which looks like below
var nestedArray = [
{ id: 1, filter: { type: "nestedArray", name: "5" } },
{ id: 2, filter: { type: "nestedArray1", name: "6" } },
{ id: 3, filter: { type: "nestedArray", name: "5" } }
];
Now here I have a duplicate object, I just want to identify the duplicates using a Lodash method. Any help is appreciated.
Have already tried map, filter options but need something in Lodash method.
You can use reject with a Property.
var myArray = [
{
"id": 1,
"filter": {
"type": "nestedArray",
"name": "5"
}
},
{
"id": 2,
"filter": {
"type": "nestedArray1",
"name": "6"
}
},
{
"id": 3,
"filter": {
"type": "nestedArray",
"name": "5"
}
}
];
var result = _.reject(myArray, ['filter.name', '5']);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
So u want to reject duplicate ones by value in filter key?
_.uniqWith(nestedArray, (x, y) => _.isEqual(x.filter, y.filter), myArray)
If you have the flexibility to use Ramda instead, it could be more concise like because of every functions are auto-curried
const rejectDuplicateFilter = R.uniqWith(R.eqProps('filter'));
rejectDuplicateFilter(myArray)

Categories

Resources