I am trying to map over array of objects which each array contains another nested array of objects. However, the map does not work on the nested array. How do I map over the contents of the nested array while keeping all the content under the same title of the parent object?
Fiddle: https://jsfiddle.net/69z2wepo/249197/
The data structure looks like:
[
{
title: "title1",
content: [
{
imageUrl: "http://placehold.it/300x300",
title: "Campaigns",
description:
"Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "Events",
description:
"Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "General",
description:
"Short description explaining the use of this design in a single sentence."
}
]
},
{
title: "title2",
content: [
{
imageUrl: "http://placehold.it/300x300",
title: "Video Template A",
description:
"Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "Video Template A",
description:
"Short description explaining the use of this design in a single sentence."
}
]
}
];
The map looks like
{dataItems.map((item, index) => {
return (
<h1>{item.title}</h1>
// for each item, loop over the content array objects
<img src={item.content.imageUrl} />
<h3>{item.content.title}</h3>
<h3>{item.content.description}</h3>
<hr />
);
})}
Since each element has a content array, you must map over content as well.
Example
{dataItems.map((item, index) => (
<div key={index}>
<h1>{item.title}</h1>
{item.content.map((c, i) => (
<div key={i}>
<img src={c.imageUrl} />
<h3>{c.title}</h3>
<h3>{c.description}</h3>
<hr />
</div>
))}
</div>
))}
This is a working example.
const dataItems = [{
title: "title1",
content: [{
imageUrl: "http://placehold.it/300x300",
title: "Campaigns",
description: "Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "Events",
description: "Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "General",
description: "Short description explaining the use of this design in a single sentence."
}
]
},
{
title: "title2",
content: [{
imageUrl: "http://placehold.it/300x300",
title: "Video Template A",
description: "Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "Video Template A",
description: "Short description explaining the use of this design in a single sentence."
}
]
}
];
class App extends React.Component {
render() {
return <div>
{
dataItems.map((item, index) => {
return ( <div>
<h1>{item.title}</h1>
{ item.content.map((c, i) => <div>
<h3>{c.title}</h3>
<h3>{c.description}</h3>
</div>)}
</div>
)
})
}
</div>
}
}
ReactDOM.render( < App / > , document.getElementById('root'));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Related
I'm looking for a way to export excel file for nested array of object using xlxs-populate library, language is reactjs. I don't see this get mention in the official document, i make sure to check thoroughly (or perhap i'm missing please be kindly leave a comment), or perhap this feature hasn't been implemented yet? I'm looking forward for your insight. For an easier depiction, here's how the data should look like:
[
{
title: "title1",
content: [
{
imageUrl: "http://placehold.it/300x300",
title: "Campaigns",
description:
"Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "Events",
description:
"Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "General",
description:
"Short description explaining the use of this design in a single sentence."
}
]
},
{
title: "title2",
content: [
{
imageUrl: "http://placehold.it/300x300",
title: "Video Template A",
description:
"Short description explaining the use of this design in a single sentence."
},
{
imageUrl: "http://placehold.it/300x300",
title: "Video Template A",
description:
"Short description explaining the use of this design in a single sentence."
}
]
}
];
I'm trying to map an array in (React js) to find out if it contains a "photographer" value, so I can display a picture saying that this specific part of the array is copyright protected (parts of these array does not contain "photographer")
This is the array I'm working with:
"collection": {
"version": "1.0",
"href": "http://images-api.nasa.gov/search?q=sun&page=1&media_type=image&year_start=2022&year_end=2022",
"items": [
{
"href": "https://images-assets.nasa.gov/image/ACD22-0003-004/collection.json",
"data": [
{
"album": [
"CAPSTONE"
],
"center": "ARC",
"title": "CAPSTONE facing the Sun (Illustration)",
"photographer": "Daniel J. Rutter",
"nasa_id": "ACD22-0003-004",
"media_type": "image",
"keywords": [
"CAPSTONE",
"NRHO",
"Cubesat",
"Artemis"
],
"date_created": "2022-02-02T00:00:00Z",
"description": "CAPSTONE, a microwave oven-sized CubeSat, will fly in cislunar space – the orbital space near and around the Moon. The mission will demonstrate an innovative spacecraft-to-spacecraft navigation solution at the Moon from a near rectilinear halo orbit slated for Artemis’ Gateway. Illustration by Daniel Rutter."
}
],
"links": [
{
"href": "https://images-assets.nasa.gov/image/ACD22-0003-004/ACD22-0003-004~thumb.jpg",
"rel": "preview",
"render": "image"
}
]
}
this is how I have mapped this array:
{data?.collection?.items?.map((items, index) => {
if(
**items.data.photographer is true (here is where I'm stuck!**
)
{
return (
*Something specific*
)
} else {
return(
something else.)}
note that I'm using
data?.collection?.items?.map((items, index) =>...
because I want to first display the {items.links}.
I also tried creating a const...
const map1 = data.collections.items.data.map(data => data);
then:
if ( map1.photographer) return ( something)
however that did not work. I have a feeling I miswrote it.
Thanks everyone for your help!
Cheers!!
Using Array.prototype.some() to identify the "photographer" property in any of the data field item.
Try like this:
function App() {
const data = {
collection: {
version: "1.0",
href:
"http://images-api.nasa.gov/search?q=sun&page=1&media_type=image&year_start=2022&year_end=2022",
items: [
{
href:
"https://images-assets.nasa.gov/image/ACD22-0003-004/collection.json",
data: [
{
album: ["CAPSTONE"],
center: "ARC",
title: "CAPSTONE facing the Sun (Illustration)",
photographer: "Daniel J. Rutter",
nasa_id: "ACD22-0003-004",
media_type: "image",
keywords: ["CAPSTONE", "NRHO", "Cubesat", "Artemis"],
date_created: "2022-02-02T00:00:00Z",
description:
"CAPSTONE, a microwave oven-sized CubeSat, will fly in cislunar space – the orbital space near and around the Moon. The mission will demonstrate an innovative spacecraft-to-spacecraft navigation solution at the Moon from a near rectilinear halo orbit slated for Artemis’ Gateway. Illustration by Daniel Rutter."
}
],
links: [
{
href:
"https://images-assets.nasa.gov/image/ACD22-0003-004/ACD22-0003-004~thumb.jpg",
rel: "preview",
render: "image"
}
]
}
]
}
};
return (
<div>
{data.collection.items.map((item, index) => {
const copyRighted = item.data.some((d) =>
d.hasOwnProperty("photographer")
);
return (
<React.Fragment key={index}>
<div>{copyRighted && "Copy Righted"}</div>
<div>{item.href}</div>
</React.Fragment>
);
})}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
I have array of objects that includes name and description. My goal here is to display the name and description dynamically in my image carousel with the help of Tiny Slider js.
I try the following attempt but failed.
Use .getElementById() to get the slider element and .map() to render the data inside the object but unfortunately the whole data was rendered in one slider only.
The actual result:
index.html
<div id="sliderCont" class="my-slider">
<div>
<div class="slide">
<div class="slide-img" style="background-image: url('src/images/img-1.jpg')">
View More
</div>
<br>
<div class="slide-info">
<h3 id="project-name"></h3>
<p id="project-description" class="subtext"></p>
</div>
</div>
</div>
</div>
app.js
const project = [
{
image: "",
name: "Project 1",
description: "Project Description here.",
},
{
image: "",
name: "Project 2",
description: "Project Description here. 2",
},
{
image: "",
name: "Project 3",
description: "Project Description here. 3",
},
{
image: "",
name: "Project 4",
description: "Project Description here. 4",
},
];
document.getElementById("project-name").innerHTML = project.map((proj) => proj.name);
document.getElementById("project-description").innerHTML = project.map((proj) => proj.description);
Tiny Slider Config
let slider = tns({
container: ".my-slider",
slideBy: 1,
speed: 200,
nav: false,
controlsContainer: "#controls",
prevButton: ".previous",
nextButton: ".next",
preventScrollOnTouch: "auto",
autoplay: true,
autoplayButtonOutput: false,
responsive: {
1600: {
items: 4,
gutter: 20,
},
1024: {
items: 3,
gutter: 20,
},
768: {
items: 2,
gutter: 20,
},
480: {
items: 1,
},
},
});
project.map((proj) => proj.name)
...returns an array:
["Project 1", "Project 2", "Project 3", "Project 4"]
When assigning this array to document.getElementById("project-name").innerHTML it is converted to the string "Project 1,Project 2,Project 3,Project 4".
So you're essentially assigning this string to the .project-name innerHTMLvalue:
document.getElementById("project-name").innerHTML = "Project 1,Project 2,Project 3,Project 4";
The same thing happens with:
document.getElementById("project-description").innerHTML = project.map(
(proj) => proj.description
);
Instead, first iterate, forEach(), over the project array, and in the loop block add a slide.
To create multiple slides use cloneNode() to copy the .slide DIV. (Since you're duplicating this DIV and it's child nodes, don't use IDs. Use class names instead: .project-name and .project-description.) And append the new node to the .slide's parentNode.
After the project array loop is exited, remove, removeChild(), the original .slide-info DIV.
const project = [
{
image: "https://source.unsplash.com/random?w=200",
url: "p1.html",
name: "Project 1",
description: "Project Description here."
},
{
image: "https://source.unsplash.com/random?w=200",
url: "p2.html",
name: "Project 2",
description: "Project Description here. 2"
},
{
image: "https://source.unsplash.com/random?w=200",
url: "p3.html",
name: "Project 3",
description: "Project Description here. 3"
},
{
image: "https://source.unsplash.com/random?w=200",
url: "p4.html",
name: "Project 4",
description: "Project Description here. 4"
},
];
// get target DIV, containing .slide-img, .project-url, .project-name, and .project-description
const slide = document.querySelector(".slide");
// iterate over project array
project.forEach(proj => {
// make a clone of .slide for new slide
const newslide = slide.cloneNode(true);
// add image background to .slide-img div
newslide.querySelector(".slide-img").style.backgroundImage = `url('${proj.image}')`;
// add url href to .project-url anchor tag
newslide.querySelector(".project-url").href = proj.url;
// add name to .project-name header
newslide.querySelector(".project-name").innerHTML = proj.name;
// add description to .project-description paragraph
newslide.querySelector(".project-description").innerHTML = proj.description;
// add slide to .slide parent
slide.parentNode.appendChild(newslide);
});
// remove original slide
slide.parentNode.removeChild(slide);
<div>
<div class="slide">
<div class="slide-img">
<a class="project-url" href="" style="color: white;">View More</a>
</div>
<br>
<div class="slide-info">
<h3 class="project-name"></h3>
<p class="project-description subtext"></p>
</div>
</div>
</div>
I'm currently working with vuejs and vuex. Here is my issue :
I have a store with all the data
state: {
articles: [{
title: "Article 1",
id: 1,
tag: "Tutorial"
}, {
title: "Article 2",
id: 2,
description: "Article 2",
tag: "Review"
}
}]
}
On the homepage, I want to display all kind of articles. On the tutorial page I only want to display articles with tag "tutorial", etc...
I'm using vue-router. I'm working with a computed property and a v-for so I can loop in the articles.
computed: {
articles() {
if (this.$route.meta.title == 'Tutorial') {
return this.$store.state.articles.tag == 'Tutorial'
}
if (this.$route.meta.title == 'Review') {
return this.$store.state.articles.tag == 'Review'
}
else if (this.$route.meta.title == 'Home') {
return this.$store.state.articles
}
}
}
I know that return this.$store.state.articles.tag == 'Tutorial' can't work, I'm looking for a way to code it correctly but I'm stuck!
Also, if you have a completely different and better way to do it, feel free to tell me!
Thank you for your time :)
As everybody mentioned you will need to use filter but as a pattern you should structure it with vuex getters
when you access properties from vuex state do not to access them directly but the correct thing is to use getters
Vuex store e.x.
const store = new Vuex.Store({
state: {
articles: [
{
title: "Article 1",
id: 1,
tag: "Tutorial"
},
{
title: "Article 2",
id: 2,
description: "Article 2",
tag: "Review"
}
]
},
getters: {
allArticles: state => {
return state.articles
},
tutorialArticles: state=>{
return state.articles.filter(article=>articles.tag=='Tutorial')
},
reviewArticles: state=>{
return state.articles.filter(articles=>articles.tag=='Review')
}
}
})
//end of vuex store
Then in your "all articles" component you use
computed:{
articles(){
return this.$store.getters.allArticles;
}
}
Then in your tutorial articles component you use
computed:{
articles(){
return this.$store.getters.tutorialArticles;
}
}
This is very important because if you need to change the code for the filter method you do it in one place and thats the purpose of using Vuex
Probably the best way is using .filter()
var obj = {state: {
articles: [{
title: "Article 1",
id: 1,
tag: "Tutorial"
}, {
title: "Article 2",
id: 2,
description: "Article 2",
tag: "Review"
}
]}}
var filtered = obj.state.articles.filter(o=>o.tag == "Tutorial");
console.log(filtered)
I got a simple json api and want to display some of objects fields with react.
The api has the following structure:
{"data" : [
0: Object
id: "1"
type: "Item"
attributes: Object
title: "lorem impsum"
body: "lorem ipsum"
1: Object
id: "2"
....
]}
And I'm trying to display attributes items(title, body)
The problem is that
this works fine and displays id
{items.map(item =>
<div>{item.id}</div>
)}
BUT
If I try to use {item.attributes.title} I receive
TypeError: Cannot read property 'title' of undefined
So item.attributes is undefined.
What's wrong here?
this is the most common error that occurs because you never know what object you are going to get from server, so it is always good way to check before accessing the data, so you can try
{item.attributes && item.attributes.title ? item.attributes.title : 'print something for missing title' }
//item.attributes && item.attributes.title means if both the values are present in Object
This should help you. I couldn't find an error in your program. So, I've created a working example to solve this.
const data = {
"data": [{
id: "1",
type: "Item",
attributes: {
title: "lorem impsum",
body: "lorem ipsum",
}
}, {
id: "1",
type: "Item",
attributes: {
title: "lorem impsum",
body: "lorem ipsum",
}
}, {
id: "1",
type: "Item",
attributes: {
title: "lorem impsum",
body: "lorem ipsum",
}
}, {
id: "1",
type: "Item",
attributes: {
title: "lorem impsum",
body: "lorem ipsum",
}
}]
}
class Sample extends React.Component{
render() {
return <div>
{
data.data.map((el) => {
return <div>
<h1>{el.id}</h1>
<div>{el.attributes.title}</div>
<div>{el.attributes.body}</div>
</div>
})
}
</div>
}
}
ReactDOM.render(<Sample/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>