Reactjs # symbol in parameter: item.enclosure.#attributes how to fix, that this is possible? - reactjs

I have a .map function in my code and Im getting data from a json output but one of the item parameters is: #attribute but I cant have an # symbol in the parameter so is there any way I can fix this?
I coudn't really find anything about this because I'm not sure what to search for except for # symbol in parameter.
this is the code I used to get the data:
this.state.news.channel.item.map(function (item, i) {
console.log(item.enclosure.#attributes)
{#attributes: {…}}
#attributes:
length: "0"
type: "image/jpeg"
url: "https://media.nu.nl/m/aoqxps0aijuy_sqr256.jpg/barnier-eu-niet-onder-de-indruk-van-no-deal-brexit-dreigement.jpg"
__proto__: Object
__proto__: Object
So how can I fix that I can have an # in the parameter and it properly gets the data from the json.

Try this:
this.state.news.channel.item.map(function (item, i) {
console.log(item.enclosure["#attributes"])
});

Retrieving the value of a property
We can retrieve the value of a property using 2 different syntaxes.
const car = {
brand: {
name: 'Ford'
},
color: 'blue',
'the color': 'blue'
}
The first is dot notation:
car.color
The second, which is mandatory for properties with invalid names, is to use square brackets:
car['the color']
or even mixing:
car.brand['name']
car['brand'].name

Related

Can't access nested stateful objects in ReactJS

I am trying to access a nested object in ReactJS. This is what the object looks like:
const characteristics = [
{ id: "geo", content: 'Geopolitical' },
{ id: "dog", content: 'Dog Loving' },
];
const starterColumns = {
"1": {
name: 'I am',
items: characteristics
},
"2": {
name: 'fullstack developer',
items: []
}
}
const [columns, setColumns] = useState(starterColumns);
This is the error I get when I try to console.log(columns['2']['items']['0']['id']):
TypeError: Cannot read property 'id' of undefined
Does this have to do with the fact that I am working with a stateful variable? Is something funky going on with the nested objects? Thanks for the help!
EDIT
The problem was that there was no object in the column so I had no object to access. Now the problem outstanding is how do I fill that void without displaying a new drag and drop piece. Thanks for helping!
EDIT
I used a try/catch statement to check the object so if it is empty, nothing happens.
Use try catch only for errors that you can't handle
To access an element use dot notation whenever it's possible instead of using bracket notation []
When there is an empty array in the items you can't access to the id you will get an error so the solution is to check if the array is not empty
columns['2'].items.length > 0
To access the first element of an array you have to use [0] instead of ['0']
try this solution
if (columns['2'].items.length > 0) {
console.log(columns['2'].items[0].id)
}

JSX: .map is not a function

I understand the source of the problem, but I'm just a bit stuck on how to resolve it.
I'm doing something like items.map(item, index), but in the browser console I get an entire object. This object has another object within it called data, and that's where I'm trying to apply the map function, since I understand it only works on arrays. The object looks like this:
{
"data":[
{"id":"1","name":"a","description":"aaaaaa"},
{"id":"2","name":"b","description":"bbbbbb"},
{"id":"3","name":"c","description":"cccccc"}
]
}
But when I try to do items.data.map, I get the error property 'data' does not exist on type 'Item[]', which is true. It only shows up in the browser console.
What am I missing and is it possible to resolve it without adding a data property?
Thank you!
data is an array, so to access its inner content, you have to apply map() in a nested manner:
items.map((item) => item.data.map((data) => /* you can access the inner data here */));
items.data.map doesn't work because the key is "data", not data
Your object keys should not be strings:
{
data: [
{id: 1, name: "a", description: "aaaaaa"},
{id: 2, name: "b", description: "bbbbbb"},
{id: 3, name: "c", description: "cccccc"}
]
}
Then you can do:
items.data.map((item, index) => ...

Why do I get TypeError: _this.data.forEach is not a function

I am trying to retrieve data from the backend. These are the relevant parts of my code:
API call
getData(PrimaryId:number):Observable<DataDto[]>{
return this.httpClient.get(`${this.prefix}/<xyz>/${PrimaryId}/xyz`) as Observable<DataDto[]>
}
Component TypeScript
onRetrieveClicked() {
this.xyzService.getData(this.PrimaryId).subscribe(
(xyz: DataDto[]) => {
this.xyz = xyz
console.log(this.xyz)
console.log(this.xyz.forEach((data)=>data.name)
})
}
First console.log output
{content: Array(1), pageable: {…}, totalPages: 1, totalElements: 1, last: true, …}
content: Array(1)
0: {name: max, name: null, asset: null, …}
length: 1
..........
But when I try to print only the name in the second console, it says that forEach is not a function. How can I solve this
edit
Dto model
export interface DataDto {
name: string
asset: abcDto
status: StatusDto
tasks: efgDto[]
nextDate: string
}
The xyz variable that you type as DataDto[], an array, is actually an object. This can be seen in your console.log, an array would be enclosed in [], not {}
is an object --> {
content: Array(1), pageable: {…}, totalPages: 1, totalElements: 1, last: true, …}
content: Array(1)
0: {name: max, name: null, asset: null, …}
length: 1
}
The data you are looking for is most likely the response object's content so add an import for import {map} from 'rxjs/operators'; and transform the data you've gotten from the response:
this.xyzService.getData(this.PrimaryId).pipe(
map((xyzResponse: any) => xyzResponse.content)
).subscribe(
(xyz: DataDto[]) => {
this.xyz = xyz;
console.log(this.xyz);
let dataNames = xyz.map(data => data.name);
console.log(dataNames);
}
I've typed xyzResponse as any but you could ofcourse create a reusable type for it if the API always returns the object with content, pageable, totalPages, ...
Rxjs is the library that Angular uses to handle asynchronous programming, such as HTTP calls or component events. Rxjs chains asynchronous manipulations together in a pipe (hence the .pipe call). Inside of this pipe rxjs expects a chain of operators that will perform operations on the asynchronous data, one by one. The map operator takes the input value and returns a new value so that the value you subscribe to has been transformed from the HTTP response to the .content field of the HTTP response.
Working in this way fixes all TypeScript compiler errors and allows you to chain additional calls later, like retrying if the API times out, or catching errors, or merging in other HTTP calls.
It seems that your this.xyz is not an array, but has an array property called content, you should modify your response object in order to accept it.
You can check if your objects are arrays with the following method
Array.isArray(obj)
Update your code to this.
this.xyzService.getData(this.PrimaryId).subscribe(
(xyz: NewObject) => {
this.xyz = xyz
console.log(this.xyz)
//If you have doubts of what is comming is nice to check if your property is an array
if(Array.isArray(this.xhy.content) {
console.log(this.xyz.content.forEach((data)=>data.name) });
}
}
Create a new object in order to support your response
class NewObject {
content: Array<DataDto>
// other values here
}
Another approach is like #Robin says in the comment
this.xyzService.getData(this.PrimaryId).subscribe((xyz: {content: DataDto[]}) =>
{
this.xyz = xyz
console.log(this.xyz)
//If you have doubts of what is comming is nice to check if your property is an array
if(Array.isArray(this.xhy.content) {
console.log(this.xyz.content.forEach((data)=>data.name) });
}
}
It's because you are trying to loop through an object instead of array
I think you can try this:
console.log(this.xyz.content.forEach((data)=>data.name) })

mongoose query: find an object by id in an array

How could I find an image by id in this Schema. I have the id of the User and the id of the image I am looking for. What would be the best way to do this and do all images in this case have different ids or could they have the same id because they don't belong to the same User?
My Schema looks like this:
var userSchema = new Schema({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
name: String,
about: String,
images: [{
id: Schema.ObjectId,
link: String,
main: Boolean
}]
});
When you are interested in the full object it is a simple find:
.find({"facebook.id":"<id>", "images.id":<image-id>})
I don't think that there is a way to reduce the image array in the result.
To update a single element in the image array you can use this:
.update({"facebook.id":"<id>", "images.id":<image-id>}, {$set : {"images.$.main" :false} } );
userSchema .find({facebook.id: "some ID",{ "images.id": { $in: [ id1, id2, ...idn] }}
since images are inside the document you can have same ID's however every time you query you should keep in mind that you send some other parameters such as facebook.id or facebook.email along with image id's to retrieve them. Otherwise you end up getting all that might be irrelevant only because you decide to keep same ID's for images.
tl;dr
I struggled with this and came up with a solution. Like you, I was trying to query for a deeply nested object by the _id, but I kept coming up empty with the results. It wasn't until I did some type checking that I realized the id value I was getting from my frontend, while directly supplied by mongoose, was in fact a String and not an Object.
I realize this question was already partially answered before, but that person's solution didn't work for me, and the comment on the answer tells me you wanted to update the specific image you queried for, which is exactly what I was trying to do.
The solution
In order to select an object from the nested array by the _id value, first you'll have to install the npm package bson-objectid and use the provided method to convert your string into an objectId in your query.
In your terminal:
npm i bson-objectid
In your code:
const ObjectId = require('bson-objectid')
userSchema.findOneAndUpdate(
{ "facebook.id": <user-id>, "images._id": ObjectId(<image-id>) },
{ "$set": { "images.$.main": false } },
{ new: true }, // an extra options parameter that returns the mutated document
(err, user) => {
if (err) {
handleErr(err)
} else {
console.log(user)
// do something with new user info
}
)

Convert an iterable map object to array object in ReactJS

I'm trying to load some json file in a DropdownList from react-widgets. When I load the json file the data type looks like this:
Map {size: 1, _root: ArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
__altered
:
false
__hash
:
undefined
__ownerID
:
undefined
_root
:
ArrayMapNode
size
:
1
__proto__
:
KeyedIterable
While the Dropdown component (from react-widgets) needs an array! So It makes this error:
Failed propType: Invalid prop `data` of type `object` supplied to `DropdownList`,
expected `array`. Check the render method of `Uncontrolled(DropdownList)`.
I can't load the json file directly and I have to use ajax to load it (or technically I can but it's a huge file and each time the user click on the dropdown list it takes couple of seconds to load the data from file). How can I convert this to an array?
P.S. The json file looks like this:
{
"items":[
{
"id": "aaa",
"name": "english"
},
{
"id": "aab",
"name": "Swedish"
},
]
}
I think you're looking for something along the lines of:
var dropdownList = jsonObject.items.map((item, i) => {
return (
<option key={i} val={item.id}>{item.name}</option>
);
})
The Array.prototype.map function simply goes over a list and produces a new list of the same size but with changes based on the modifier/callback function.
Update based on comment:
Based on the docs for DropdownList, you have two options for passing data to the list: a flat array of item names, or a list of objects with specific keys for the item name and value.
Option 1: flat list of item names
var itemNames = jsonObject.items.map((item) => item.name );
Option 2 : list of objects
var items = jsonObject.items.map((item) => {
return {
textField: item.name,
valueField: item.id
}
});
The benefit to using the second option would be when someone selects one of the items, the event that is created with point to the val attribute of the HTML <option>. This is useful for you especially since your ids and names are not the same. An example:
Option 1 (from above):
<DropwdownList
data={itemNames}
onSelect: (event) => {
// Will give the `val` attribute set by DropdownList
// This might be the item name, or it might be something unique to DrowdownList
console.log(event.target.value);
}
/>
Option 2 (from above):
<DropwdownList
data={items}
onSelect: (event) => {
// Will give the `valueField` attribute you set, which for you is the item's `id` field
// This might be the item name, or it might be something unique to DrowdownList
console.log(event.target.value);
}
/>

Resources