I'm fetching data from redux store with useSelector.
const customerProduct = useSelector((state) => state.objects.customersProducts[match.params.customerProductId]);
If I log the data it is displayed like this in the console:
Once I try to use spread operator to create a new object, it would lose all the values with (...).
Like this:
const updatedCustomerProduct = { ...customerProduct, newValue: "abc" };
I would get an output like this:
const uptdatedCustomerProduct =
{
"id": "AALzgGxtlg",
"_objCount": 6360,
"newValue": "abc",
"className": "customerOfferMetadata"
}
What's going on here? How could I handle these values? If I copy the object from the console the object is perfectly visible.
Even in redux dev tools the data is displayed like this:
{
"entityInfo": {
"productId": 441,
"bundleOfferId": 22
},
"title": {
"us": "Special Offer"
},
"desc": {
"us": "6 months"
},
"order": 0,
"enabled": true,
"entityType": "product",
"detailsUrl": "www.google.com",
"thumb": {
"__type": "Pointer",
"className": "Resource",
"objectId": "12345"
},
"createdAt": "2021-02-26T18:48:25.358Z",
"updatedAt": "2021-09-21T21:41:49.384Z",
"clientId": 1,
"objectId": "AALzgGxtlg"
}
I'm not sure what code is generating those objects for you, but when you see properties in the console that are semitransparent, they are non-enumerable. This means that when applying the spread operator, they are not iterated over, and hence they do not make it into the new object.
To make all properties enumerable, check out the question Make all properties enumerable.
Related
I'm trying to store in MongoDB one document with an object with the properties I want to map latter. My idea it's to create a function that will receive 2 params. First the object where I got to find the mapping, and second the object where I have to take the info from.
For example I want to store this JSON (that would be the first parameter in the function):
{
"name": "client.firstName",
"surname": "client.surname",
"age": "client.age",
"skills": [
{
"skillName": "client.skills[index].name",
"level": "client.skills[index].levelNumber",
"categories": [
{
"categoryName": "client.skills[index].categories[index].name",
"isImportant": "client.skills[index].categories[index].important"
}
]
}
]
}
And the second paramenter would be something like this (it's the object where you find the information.
{
"client": {
"firstName": "Jake",
"surname": "Long",
"age": 20,
"skills": [
{
"name": "Fly",
"level": 102,
"categories": [
{
"name": "air",
"important": true
},
{
"name": "superpower",
"important": false
}
]
},
{
"name": "FastSpeed",
"level": 163,
"categories": [
{
"name": "superpower",
"important": false
}
]
}
]
}
}
The idea it's: with de paths that I have in the first object, find it in the second one.. The problem I found it's when I have arrays, because when I defined the mapping rules I don't know how many positions will have the array I want to map. So in the mapping object (first) I'll only define the path but I'll not put it with the same lenght of the secondone because I don't know how much it will have.
I'm trying to loop my child array but it's not working. It's working fine which it's first items but not working on the child elements.
"candidateApplication": [
{
"label": "Are you currently attending school?",
"id": "ap_currentschool",
"value": "",
"required": "N",
"type": "radio",
"display": null,
"list": [
{
"searchCode": "yes",
"searchValue": "yes"
},
{
"searchCode": "no",
"searchValue": "no"
}
],
"onSelect": [
{
"yes": [
{
"label": "Estimated Completion Date",
"id": "ap_compdate",
"value": "",
"required": "N",
"type": "date",
"display": null,
"list": null,
"onSelect": null
}
],
"no": null
}
]
},
]
I am easily access my data to looping lists like obj.candidateApplication.list But I am not able to loop through obj.candidateApplication.onSelect.yes.
Can anybody please guide me how can I fix that issue.
enter image description here
You are accessing obj.candidateApplication.onSelect.yes which is undefined because obj.candidateApplication.onSelect is an array of objects.
You probably want to loop over obj.candidateApplication.onSelect and then for each object you can access the yes property as you wish:
$.each(onSelect, function (index, element) {
$.each(element.yes, function (x, y) {
// your code here
})
});
Edit: As pointed by Heritic Monkey in the comments, obj.candidateApplication is an array as well, but in the picture attached to the question, there's already a local variable called onSelect, loop through that instead of obj.candidateApplication.onSelect because it's undefined. (at least it should be, we don't know what your code is doing)
I've got a simple JSON data array that looks like this (it's the same in my Redux store and I store it under properties):
[
{
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
{
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
]
It has to be an array because I'm mapping over it:
{properties.map(property =>
<Property
id={property.id}
name={property.name}
description={property.description}
foo={property.foo}
/>)}
This way I have two properties rendered in my app.
The question is - how do I update "foo"in Redux?
This my reducer currently written according to the docs:
case 'UPDATE_FOO':
return {
...state,
properties: {
...state.properties,
[action.id]: {
...state.properties[action.id],
foo: action.fooData,
}
}
}
Of course it throws TypeError: Cannot read property 'room' of undefined because I'm trying to access state.properties["room"] and this does not exist.
I've been thinking about reshaping my JSON and Redux store, but once I change it to named objects I can't map over it...
Thank you!
Change your store to be an object, and generate the array, when you need to render it, by converting it to an array, using Object.values():
{Object.values(properties).map(property => (
<Property key={property.id} {...property} />
)}
If the order might change (sorting for example), you need to have another array with the ids to hold the order (see redux normalized state):
{
properties: {
room: {
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
apartment: {
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
}
}
{
properties: {
room: {
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
apartment: {
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
},
order: ['apartment', 'room']
}
{order.map(id => (
<Property key={id} {...properties[id]} />
)}
If you want to update the store using but the Id. You can look up for the one element (you're trying to edit) in array of properties using the id, then to update it:
case 'UPDATE_FOO':
const newProperties = state.properties.map(property => {
if(property.id === action.id) {
return { ...property, foo: action.fooData}
}
return property;
})
return {
...state,
properties: newProperties
}
}
I have two arrays of object, the first array (printers, around 80 elements) is made of the following type of objects:
[{
printerBrand: 'Mutoh',
printerModel: 'VJ 1204G',
headsBrand: 'Epson',
headType: '',
compatibilty: [
'EDX',
'DT8',
'DT8-Pro',
'ECH',
],
cartridges: [],
},
....
]
The second array (cardridges, around 500 elements) is made of the following type of objects:
[
{
"customData": {
"brand": {
"value": {
"type": "string",
"content": "ECH"
},
"key": "brand"
},
"printer": {
"value": {
"type": "string",
"content": "c4280"
},
"key": "printer"
}
},
"name": "DT8 XLXL",
"image": {
"id": "zLaDHrgbarhFSnXAK",
"url": "https://xxxxxxx.net/images/xxxxxx.jpg"
},
"brandId": "xxxxx",
"companyId": "xxxx",
"createdAt": "2018-03-26T14:39:47.326Z",
"updatedAt": "2018-04-09T14:31:38.169Z",
"points": 60,
"id": "dq2Zezwm4nHr8FhEN"
},
...
]
What I want to do first is to is to iterate through the first array and and then iterate for all the cardridge available: if a the value customData.brand.value of a cardridge is included inside the array 'compatibility' of a printer, then I have to add this cardridge object inside the cardridges array of this printer. I have tried but somehow the iteration doesn't take place correctly. This is what I tried:
printers.forEach((printerItem) => {
const printer = printerItem;
printer.compatibilty.forEach((compatibilityItem) => {
const compatibility = compatibilityItem;
cardridges.forEach((cartridge) => {
if (compatibility === cartridge.customData.brand.value.content) {
printer.cartridges.push(cartridge);
}
});
});
});
What am I doing wrong?
You're accessing the wrong property. It should be cartridge.customData.brandName.value.content, carefully note brandName.value rather than brand.value
Your issue is that you're accessing it by the wrong property - brand and not brandName.
Furthermore, if you're targeting everything but IE, you could simplify your nested for loops to utilize some fancy ES6 array methods.
printers.forEach((p) => {
p.cartridges.push(cartridges.filter((c) => {
const brandName = c.customData.brandName.value.content;
return p.compatibilty.includes(brandName);
}));
});
Am getting Data from server in below JSON format
{
"Data": [
{
"Id": "1",
"Number": 0,
"Modify": {
"Id": 0,
"Name": "a"
}
},
{
"Id": "2",
"Number": 1,
"Modify": {
"Id": 1,
"Name": "b"
}
}
]}
And am trying to create a new copy(Rename) of Modify inside the same object because my other data is expecting JSON with same format but different name for modify.
So i though i would foreach and create copy of the same which will form like below
{
"Data": [
{
"Id": "1",
"Number": 0,
"Modify": {
"Id": 0,
"Name": "a"
},"New": {
"Id": 0,
"Name": "a"
}
},
{
"Id": "2",
"Number": 1,
"Modify": {
"Id": 1,
"Name": "b"
},
"New": {
"Id": 1,
"Name": "b"
}
}
]}
Is there a better approach i can rename the object or should i create a copy. What is the better way to copy ?
Thanks
For loop is a fine way to do that.. data[i].Name = data[i].Modify;. Im fairly sure there isn't a "better" way than this in Javascript.
There's no other way than the one suggested by #MjrKusanagi, nevertheless I suggest another approach.
Make a function that takes your original object and replaces the selected key with the new name, returning a new object without changing the original one (immutability)
The function could take 3 arguments:
function modifyObject(object, oldKey, newKey) {...}
Inside the function you could use the Object.assign method to create a copy of the original object (a copy, not a reference):
var newObj = Object.assign({}, object);
After that, you can change the key name by creating a new one and don't forget to remove old key from the new object:
newObj.newKey = newObj.oldKey;
delete newObj.oldKey,
Finally you can return this new object and even use this function every time you need to do anything similar.
Using the delete is considered bad practice, but at least here you are not mutating your original source, so you can depend in its content over all your application's life cycle.