Get access to an array in an array from REST API - reactjs

Hi I'm trying to display variants in two separate categories Color and Size, to do this I need to get data from the api, I can access "attributes", but I would like to be able to access 0 and 1 and map them, I have no idea how to do this.
{variants.length > 1 ? (
variants.attributes.map(({ name, values }) => (
<ProductOptions
key={`key-${name}`}
name={name}
values={values}
selectedOptions={selectedOptions}
setOptions={setOptions}
/>
))
) : (
<Fragment />
)}
Thank you so much!

As i understand the output of Array with 6 elements where each of that 6 has attributes and attributes is yet another array and you want to loop through those attributes so you need 2 loops. One to loop through parent array and seconds inside the child.
variants.map((variant) => {
variant.attributes.map((attribute) => {
console.log('attribute: ', attribute);
console.log('attribute id: ',attribute.id);
});
});
p.s. you may use forEach https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach but it has little difference in this case.
Also it seems like you working with ReactJS and building some JSX to put into rendered jsx. I would argue to form the array upfront and in final jsx just insert the rows, so your final jsx will be more readable, especially in cases of double loops or any more complex jsx.
const attributes = [];
variants.map((variant) => {
variant.attributes.map((attribute) => {
console.log('attribute: ', attribute);
console.log('attribute id: ',attribute.id);
attributes.push(<div key={attribute.id}>{attribute.id}</div>)
});
});
// later
return (
<div>
{attributes}
</div>
)

Related

Remove duplicate JSX elements | React Strapi graphql

Long story short, i have and array of JSX elements, that looks something like this:
<ChatListCard
key={index}
prop1={prop1}
prop2={prop2}
prop3={prop3}
/>
I get the props for these "Cards" from two different tables in Strapi/Graphql API, so I do something like this:
[].concat(
array1.map((item,index)=> <Card key={index} prop1={item.prop1} ... />),
array2.map((item,index)=> <Card key={index} prop1={item.prop1} ... />)
)
The problem is that array1 and array2 contain some "items" that are identical, and need to be filtered out. Is there a way to do it, using JS:
[].concat(...).filter((magic)=> magic but filtered) //use the filter here
, or i should do it in GraphQL.
(I have already used where clause in there to filter out only the items that I do not need)
query ProposalsAndRequests($input:String!){
proposals(where: {_or:[
{owner:{email:$input}}
{task:{owner:{email:$input}}}
]},sort:"created_at:desc"){
id
...
}
}
chatRequests(where:{_or:[
{users_permissions_user:{email:$input}}
{task:{owner:{email:$input}}}
]},sort:"created_at:desc"){
id
...
}
}
note: chatRequests and Proposals contain identical fields, they just serve different purposes elsewhere in the site
the users_permissions_user and owner are also the same relation
You can do it using the "Set" datastructure in js. const set = new Set(arr);. Sets cant have duplicates! :-) but they can have identical objects if the references are not the same.
For a more complex filter, use .reduce function to accumilate only uniques.
Or, you could remove the duplicates by bruteforce it with something like:
const noDubs = [];
myArr.foreach(item => {
if(!noDubs.some(entry = entry.special.property === item.special.property) noDubs.push(item);
});

Printing data from array using shorthand

I am using react-admin framework and I am trying to print data from my array.
My array is looking like this:
enter image description here
As you can see it currently has 3 indexes. Each of them stores different data. I want to print these data on to same page.
I am aware that I need to use some sort of cycle (for, foreach), but I really dont know how to implement it in shorthand.
This is my code, that I need to loop:
ID: {this.state.source[index].Id}<br></br>
AuditDate: {this.state.source[index].AuditDate}<br></br>
UserId: {this.state.source[index].UserId}<br></br>
Resource: {this.state.source[index].EntitySet}<br></br>
Entity1: {this.state.source[index].Entity1}<br></br>
Entity2: {this.state.source[index].Entity2}<br></br>
Operation: {this.state.source[index].Operation}<br></br>
EndPoint: {this.state.source[index].EndPoint}<br></br>
Changes: {this.state.source[index].Changes}<br></br>
Any ideas how to loop this?
Thank you in advance
You can make use of map to iterate over array,
{
this.state.source && this.state.source.length > 0 && this.state.source.map(source => {
return <>
<div>ID: {source.Id}</div>
<div>AuditDate: {source.AuditDate}</div>
<div>UserId: {source.UserId}</div>
<div>Resource: {source.EntitySet}</div>
<div>Entity1: {source.Entity1}</div>
<div>Entity2: {source.Entity2}</div>
<div>Operation: {source.Operation}</div>
<div>EndPoint: {source.EndPoint}</div>
<div>Changes: {source.Changes}</div>
</>
})
}
renderSources() {
const sources = source.map((eachSource) => {
return (
<div>
<span>`ID: ${eachSource.Id}`</span>
<span>`AuditDate: ${eachSource.AuditDate}`</span>
<span>`UserId: ${eachSource.UserId}`</span>
<span>`Resource: ${eachSource.EntitySet}`</span>
<span>`Entity1: ${eachSource.Entity1}`</span>
<span>`Entity2: ${eachSource.Entity2}`</span>
<span>`Operation: ${eachSource.Operation}`</span>
<span>`EndPoint: ${eachSource.EndPoint}`</span>
<span>`Changes: ${eachSource.Changes}`</span>
</div>
);
});
return sources;
}
render() {
return (<div>{this.renderSources()}</div>);
}

Conditional classes on single instances of component within a loop

I have a loop of components that make a grid and I want some instances to have a background color change triggered by adding a class.
This question gave me ideas but I've yet to get them to work.
I have this basic markup in it.
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
And I have an array of the indexes representing the component instances that I want the color changed on
let indexes = [101, 178, 232, 545]
Currently I am doing it with plain JS, via document.querySelector('.box:nth-of-type(101'), but as this method bypasses React I want to change it.
Based on the other question I tried making an array of all the components and setting that to state, then looping through and using the indexes. I don't know how to "access" the component like this and get $$typeof: Symbol(react.element) etc
let compArr = []
this.arr.map((i) => {
compArr.push(
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
)
})
this.setState({
compArr: compArr
})
Then later loop over indexes:
indexes.map(index => {
this.state.compArr[index] ===> ??stuck here??
})
Expected Output: So on an array of three instances, say I want the second one only to have the class of backgroundColor:
<div className='box' </div>
<div className='box backgroundColor'</div>
<div className='box'</div>
Only in my case, I want the instances to correlate with the indexes array
How can I set the conditional class to true in those instances I have in the array? Say I have like 500+ instances total.
If I understand you correctly this is proably what you're looking for...
let indexes = [101, 178, 232, 545]
let compArr = this.arr.map((obj, i) => {
return (
<div
className={`box${( indexes.includes(i) ? " backgroundColor" : "")}`}
key={i}
>
</div>
);
})
this.setState({
compArr: compArr
})
If your goal is only to return the given div with the className backgroundColor for every element in this.arr with its index included in the indexes array then...
You only need to iterate over the array once and can perform all the necessary logic you're currently doing performing in two.
You don't need to use Array.push() to an outside collector when using any of the pure functions like map() or reduce() because they return a new version of whatever array is iterated over.
If for whatever reason you want a distinct array of <div>s with an index in indexes then you should use reduce...
let compArr = this.arr.reduce((acc, obj, i) => {
if (!indexes.includes(i)) return acc;
return [
...acc,
<div className="box backgroundColor" key={i}></div>
)]
},[])

React save the value of current state and make it unchangeable

I am new to React and I have a problem considering saving the value of current state. I am not sure if it is possible.
To summarise, I have build up a function which returns a HTML element as below. The idea is to save a div on each click.
createQuestion(){
let CurrentQuestion=this.state.freetextinput;
return this.state.values.map((el, i) =>
<div key={i} className="QuestionBox">
{CurrentQuestion}
</div>
)
}
The value of freetextinput changes on each click. The idea is to save all the value of freetextinput. Say, the values of freetextinput are 1, 2, 3. I would like to have all of the three values:
1
2
3
However, I only get something like this:
3
3
3
I wonder, if there is a way to save/store the value of this.state.freetextinput, such that I can get all the three values.
The new question needs to be pushed into an array before it can be mapped. Might something like this work for you?
var savedQuestions = []
createQuestion(q){
savedQuestions.push(q)
this.setState({savedQuestions: savedQuestions}, () => {
var questionElements = this.state.savedQuestions.map((el, i) =>
<div key={i} className="QuestionBox">
{el}
</div>
)
})
return questionElements
}
Save every input of free text input into an array, that way you would get access to all the values:
You can check this code sandbox: https://codesandbox.io/s/j835121kv
You should map this.state.freetextinput directly :
Since freetextinput is a string, you will need to convert it to an array first using split
createQuestion(){
return this.state.freetextinput.split(', ').map(el =>
<div key={el} className="QuestionBox">
{el}
</div>
)
}
This will work if your string looks like : "1, 2, 3"
If your string is "123" then use split('') instead of split(', ')

ReactJS - Listing all keys at once

I'm a beginner of ReactJS and I'm stuck trying to figure out why map only returns a single prop at a time.
In file1.jsx, I have an array that contains 3 objects:
var MainPanelOneData = [{"id":1,"shotviews":15080},{"id":2,"likes":12000},{"id":3,"comments":5100}];
File1.jsx also has a render function to extrapolate the data inside the array:
render: function() {
var ListMainPanelOne = MainPanelOneData.map(function(data) {
return <MainPanelOne key={data.key} shotviews={data.shotviews} likes={data.likes} comments={data.comments} />
});
In file2.jsx, I have this code to render the data object from file1.jsx:
render: function() {
return (
<div>
<span>{this.props.shotviews} shot views</span>
<span>{this.props.likes} likes</span>
<span>{this.props.comments} comments</span>
</div>
)
}
The result shows this:
15080 shot views likes comments
shot views12000 likes comments
shot views likes5100 comments
I'm guessing it repeats like this because it searches through one key at a time? If that's the case, how do I display all keys at the same time? Use indexing?
well your array of data doesnt have all the keys. each one of your objects in PanelOneData has ONE key and is missing the other two; additionally none of them have key called key. so youre making three MainPanelOne components, each with a single prop. the result of that map is this
[
<MainPanelOne key={null} shotviews={15080} likes={null} comments={null} />,
<MainPanelOne key={null} shotviews={null} likes={12000} comments={null} />,
<MainPanelOne key={null} shotviews={null} likes={null} comments={5100} />
]
which is an accurate display of what youre seeing
To get one line you might do something like this.
render: function() {
var ListMainPanelOne = MainPanelOneData.map(function(data) {
return <span key={data.id}> {data.shotviews} {data.likes} {data.comments} </span>
});

Resources