use react render a nested object in jsx - reactjs

I am trying to render a nested object from a firestore database in react jsx with the map function. The 'text' property like 'I will save document" is contained within what appears to be an object(document) that contains an array[blocks] that contains another array[inlineStyleRanges] that contains an object (text). I am trying to render the text object and I am having a hard time figuring out the syntax to make it render correctly.
The object has this structure:
(4) [{…}, {…}, {…}, {…}]
0:
description: "Lorem ipsum dolor sit amet, suspendisse velit"
document:
blocks: Array(1)
0:
data: {}
depth: 0
entityRanges: []
inlineStyleRanges: []
key: "8u7m4"
text: "I will save this document."
type: "unstyled"
__proto__: Object
length: 1
__proto__: Array(0)
entityMap: {}
__proto__: Object
id: Timestamp {seconds: 1551856294, nanoseconds: 879000000}
title: "TCC/NIBF SUMMARY SHEET"
__proto__: Object
my attempted render method looks like this:
render() {
const urlID = this.state.urlID;
const results = this.state.documents;
const postList = results.map((result, index) => {
if (urlID === result.id.seconds.toString()) {
return (
<Card key={result.id.seconds}>
<CardBody>
<CardTitle>File Name: {result.title}</CardTitle>
<CardText>File Description: {result.description}</CardText>
{/*<CardText>File Document Text: {result.document... }</CardText>*/}
</CardBody>
</Card>
);
} else {
return null;
}
});
return <div>{postList}</div>;
}

I used the new es6 Map function to make a new object map that I turned into an array using the spread operator and then looked at the structure of the object as an array in chrome dev tools.
After studying it, I found the correct syntax:
<CardText>File text: {result.document.blocks["0"].text}</CardText>

Related

Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead

I am having trouble on posting the lists of data in my table, I hope you guys can help me with this issue, this is the error i am getting Error: Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead.
const columns = [
{
name: "name",
label: "Name",
options: {
filter: true,
sort: true,
}
},
{
name: "dateregistered",
label: "Date Registered",
options: {
filter: true,
sort: false,
}
},
{
name: "department",
label: "Department",
options: {
filter: true,
sort: false,
}
},
];
const data = [
posts.map(post => [{name: 'post.firstname', dateregistered: 'post.date', department: 'post.department'}])
];
return (
<>
<MUIDataTable
title={"Deactivated Users"}
data={data}
columns={columns}
options={options}
/>
</>
)
I see two problems in your data constant. The first one, the .map method returns an array, so there is no need to wrap that value inside an array keys []. The other problem is that you are wrapping the .map return state object in array keys too, that is why the error of creating an object is displayed, because you are returning arrays inside the main mapped array [[{ name: ... }], [{ name: ... }]].
So basically the solution for your issue would be:
const data = posts.map(post => ({name: 'post.firstname', dateregistered: 'post.date', department: 'post.department'}))
Where the parenthesis allows the map method to directly return the object.
The issue is that data is being created as an array in an array in an array. This is why when you try const data = posts.map(post => ...) the error persists, as there is still an array in an array. After you try the above, also re-write
post => [{name: 'post.firstname', dateregistered: 'post.date', department: 'post.department'}]
to
post => ({name: 'post.firstname', dateregistered: 'post.date', department: 'post.department'})
(Changing the square brackets to round)
P.S When you map over posts to build the data, you build a object with the the key "name" and the value "'post.firstname'". That value is a string literal and not accessing some other JS object (It will make "post.firstname" the value for all the post's. Same goes for the other keys.

can't query results of graphql query because am using 2 arrays within each other

Here is my map function, I am using react with gatsby.
when I run my graphiql browser, (an IDE graphql playground) I get group as an array, and edges is also an array.
the query is a static query and the mapping function is inside of a class based react component
{group.map(({ edges }) => {
console.log(group);
edges.map(index => {
return <p>Hello</p>
});
})}
However, the p tags are not displaying anything, but if I console.log("hello") it consoles hello 4 times, anyone got any ideas?
I am a little stumped.
the console.log returns
(3) [{…}, {…}, {…}]
0:
edges: Array(2)
0:
node: {tune: "awesome", title: "Awesome Song", playtime: "2:50", page: "249", filesize: "1.8", …}
__proto__: Object
1:
node: {tune: "awesome", title: "AwesomeSong 2", playtime: "4:05", page: "525", filesize: "2.6", …}
__proto__: Object
length: 2
__proto__: Array(0)
__proto__: Object
1:
edges: Array(1)
0:
node: {tune: "decent", title: "Awesome Song3", playtime: "4:06", page: "719", filesize: "2.4", …}
__proto__: Object
length: 1
__proto__: Array(0)
__proto__: Object
2: {edges: Array(1)}
length: 3
__proto__: Array(0)
Have you tried something like this?
{group.map(({ edges }) => {
return edges.map(({node})=> {
return <p>{node.title}</p>
});
})}
You need to return something in your first map() loop.
In addition, are you displaying the loop in a render() function? If not, you can't display a <p> tag.

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) })

jest shallow render find by class excluding

I am testing a class like:
const wrapper = shallow(<Features {...props}/>);
expect(wrapper.find('.Feature__Item:not(.Feature__Showmore)').length).toBe(2);
But, I am getting an error like this:
Error: Enzyme::Selector does not support pseudo-element or pseudo-class selectors.
How can I work around this limitation?
Update: Interesting observation, when I wrote the following in the debug console: wrapper.find('.Feature__Item').findWhere(a => a.hasClass('Feature__Showmore') === false).length
The output was:
0:Object {nodeType: "host", type: "li", props: Object, …}
1:Object {nodeType: "function", type: , props: Object, …}
2:Object {nodeType: "host", type: "li", props: Object, …}
3:Object {nodeType: "function", type: , props: Object, …}
I found another way which did the trick:
expect(wrapper.find('.Feature__Item').not('.Feature__Showmore').length).toBe(2);
You could try with findWhere:
expect(wrapper.find('.Feature__Item').findWhere(a => a.hasClass('Feature__Showmore') === false).length).toBe(2);
This will first get all the elements having class Feature__Item and then exclude from this list the ones which don't have Feature__Showmore class.

Dynamically render ACF fields from wordpress rest api in react

I'm trying to dynamically map out the response that i get from the wordpress rest api. The problem I'm having is that the response im getting looks like this:
(2) [{…}, {…}]
0
:
{id: 18, date: "2018-05-02T14:31:37", date_gmt: "2018-05-02T14:31:37", guid: {…}, modified: "2018-05-02T14:51:14", …}
1
:
{id: 17, date: "2018-05-02T14:31:18", date_gmt: "2018-05-02T14:31:18", guid: {…}, modified: "2018-05-02T14:51:23", …}
length
:
2
__proto__
:
Array(0)
Both these objects have another object inside them called acf that includes my fields that i want to render out.
This is how i want to render the fields:
const dateData = [
{
date: '18-04-23',
time: '9pm',
title: 'MGM Grand Garden Arena',
},
{
date: '18-04-23',
time: '9pm',
title: 'MGM Grand Garden Arena',
},
{
date: '18-04-23',
time: '9pm',
title: 'MGM Grand Garden Arena',
},
]
const dateRender = dateData.map((t, i) => (
<div key={i} className="date-item">
<p>{t.date}</p>
<p>{t.time}</p>
<p>{t.title}</p>
</div>
));
But it's not working because the acf fields is nested inside two different objects. The purpose of this is that the user should be able to add new dates in wordpress dashboard and it should render it out dynamically. Any tips?
Thanks!

Resources