Render object arrays in react function - javascript

Forgive me, I'm a react noob. I'm trying to access the data inside a javascript/react object. The json data looks like this:
"schoolData": {
"student": [
{
"name": "blah",
"type": "lorem",
"grade": 90,
}
],
"class": null
},
What I'm trying to display is essentially just like this...
Student
name: Blah type: lorem grade: 90
Class
--- no data here ---
So I'm trying like this:
import React, { PropTypes } from 'react';
const SchoolDataPropTypes = {
SchoolData: PropTypes.object.isRequired,
};
function School(props) {
return (
<div className="section">
<h3 className="head">School Data</h3>
<div className="row">
<ul className="Uli">
{(props.data || []).map(function(value) {
return <label>{props.data.key}</label><li key={value}>{key}: {value}</li>
})}
</ul>
</div>
</div>
);
}
School.propTypes = SchoolPropTypes;
export default School;
It obviously doesn't work. So that I can render each array inside the object?

Ideally, you would manually specify each key.
{(schoolData.student || []).map(student => (
<ul className="Uli">
<li>Name: {student.name}</li>
<li>Grade: {student.grade}</li>
</ul>
))}
etc...
But if you really want to loop through variable keys in the student object then basically you need to loop through the student array, and then loop through the keys in each student object. Here's what it might look like:
const School = ({ schoolData }) => (
<div className="section">
<h3 className="head">School Data</h3>
<div className="row">
{(schoolData.student || []).map(student => (
<ul className="Uli">
{Object.keys(student).map(key => (
<li key={key}>{key}: {student[key]}</li>
))}
</ul>
))}
</div>
</div>
);
-
<School schoolData={schoolData} />
If you're targeting very, very old browsers you may need a polyfill for Object.keys

Related

How to declare file-path in Javascript for object mapping?

I am working on a personal react project for learning and considering to mapping data from a JavaScript object file (not JSON in this case). There are many ways to do it. This method of works for me
import product1 from "../../assets/images/products/product1.jpeg";
<img src={ product1 } alt="item_image" />
But I want to do it differently. I want retrieve data from a JavaScript object file (not JSON) using mapping. My data.js file contains data like this-
const data = [
{
id: 1,
title: "Meat",
price: €2.5,
category: "Grocery",
path: "../../assets/images/products/product1.jpeg",
},
{
id: 2,
title: "Milk",
price: €1.25,
category: "Drink",
path: "../../assets/images/products/product2.jpeg",
}
]
export function getData () {
return data;
}
and mapping data in this way
import { getData } from "./data";
function Product () {
const product = getData();
return (
<>
{
product.map((item) => (
<div>
<div>
<div>
<div>
<span> { item.title } </span>
</div>
<div>
<span> { item.price } </span>
</div>
</div>
<div>
<img src={ item.path } alt="item-img" />
</div>
<div>
<div>
<span> { item.category } </span>
</div>
</div>
</div>
</div>
))
}
</>
);
}
export default Product;
But I failed to get the image from this. After looking on internet, I tried to declare the path property using this method path: "file:///home/user/Documents/testapp/src/assets/images/products/product1.jpeg"
Unfortunately this method also failed to get the product image. I am expecting a better solution from the community. --Thanks.

How to add an image in the first react component and ignore in rest of the components using map function

I'm trying to add content into a component using json file where I require only the first component to have the cover image and rest of the components to ignore it.
Schema: "TrackList": [
{
"CourseNo": "1",
"CourseName": "C++ Programming with DataStructures",
"CoverImg":"example.com/cover.jpg"
},
{
"CourseNo": "2",
"CourseName": "Competitive Programming"
},
{
"CourseNo": "3",
"CourseName": "Java"
}
]
the below code renders as required but it also adds blank image into components except the first one.
render(){
const { Data } = this.props;
const Courses = Data.TrackList.map(course => {
return (
<li>
<span>Course {course.CourseNo}</span>
<a href='#path-10'>{course.CourseName}</a>
<img src={course.CoverImg}/>
</li>
)
});
return(
<div className='col-md-4 right-pannel'>
<ul>
{Courses}
</ul>
</div>
)
}
Array.prototype.map calls the provided callback function with the current array index (as the second argument). The first index of an array is 0, so you just need to add some logic that makes sure the image is only added when the index is equal to 0, like this:
const Courses = Data.TrackList.map((course, i) => {
return (
<li>
<span>Course {course.CourseNo}</span>
<a href='#path-10'>{course.CourseName}</a>
{ i === 0 && <img src={course.CoverImg}/> }
</li>
)
});
And here's a slightly modified version of your code turned into a runnable snippet:
const Data = {"TrackList": [{"CourseNo": "1","CourseName": "C++ Programming with DataStructures","CoverImg":"example.com/cover.jpg"},{"CourseNo": "2","CourseName": "Competitive Programming"},{"CourseNo": "3","CourseName": "Java"}]}
const Courses = Data.TrackList.map((course, i) =>
<li>
<span>CourseNo: {course.CourseNo}</span>
<span> | CourseName: {course.CourseName}</span>
{ i === 0 && <span> | CoverImg: {course.CoverImg}</span> }
</li>
);
ReactDOM.render(
<div className='col-md-4 right-pannel'>
<ul>
{Courses}
</ul>
</div>,
document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Or more generic solution can be the below code, as can be seen in your data, other object does not have CoverImg key.
const Courses = Data.TrackList.map(course => {
return (
<li>
<span>Course {course.CourseNo}</span>
<a href='#path-10'>{course.CourseName}</a>
{course.CoverImg && <img src={course.CoverImg}/>}
</li>
)
});
You can put condition with && to render only object which is having image
Optimized
-Unique key for every row
-&& condition for available image path
-another way removing return(){}
Code
render() {
const { Data } = this.props;
const Courses = Data.TrackList.map(course => (
<li key={course.CourseNo}>
<span>Course {course.CourseNo}</span>
{course.CourseName}
{course.CoverImg && <img src={course.CoverImg} alt="imgicon" />}
</li>
));
return (
<div className="col-md-4 right-pannel">
<ul>{Courses}</ul>
</div>
);
}

is there a way to query data based on a particular item from a json object?

I have user interface which looks should look like this
and that picture above is just pure HTML.
So when I tried to create it with React, I am failing to align the tv shows with a particular TV channel overflowing horizontally as per the channel.
Picture of what I get in React
I am querying the data from json files that have the objects and the TV channel object looks like
{
"groupID": 16481,
"hasMediathek": true,
"storeUrlAndroid": null,
"storeUrlApple": null,
"liveWeb": "https://www.zdf.de/live-tv",
"liveApp": null,
"defaultOrder": 1000,
"hdp": false,
"quality": 2,
"name": "ZDFneo HD",
"isEncrypted": false,
"isHD": false,
"dvbTriplet": "dvb://0.0.0",
"id": null,
"major": true
}
this is connected to the shows through its groupID which shows up as channelID in the shows Object. Below is a sample for the shows object
{
"_id": "5b1f5c7da6cdf0cbbdb7e700",
"showID": 892149863,
"channelID": 16481,
"title": "Masters of Sex",
"subtitle": "Auf frischer Tat ertappt (Dirty Jobs)",
"serie": {
"no": "4",
"title": "Auf frischer Tat ertappt",
"seasonno": "2",
"info": "Staffel 2 | Folge 4"
}
this what I have done to query the data for channels
import stations from "../data/channels.json";
import data1 from "../data/1.json";
import data2 from "../data/2.json";
import data3 from "../data/3.json";
import data4 from "../data/4.json";
import data5 from "../data/5.json";
import data6 from "../data/6.json";
class Contents extends React.Component {
constructor(){
super();
this.trans = this.trans.bind(this);
}
station = { ...stations };
shows = { ...data1, ...data2, ...data3, ...data4, ...data5, ...data6 };
trans(){
Object.values(station.result.channels).map(value => {
console.log(value["groupID"], "odgdggddgdd");
return value["groupID"];
});
}
render() {
return (
<Fragment>
<TopNavBar />
<BottomNavBar />
<div className="row">
<section className="left-menus">
<div className="left-items">
{Object.values(station.result.channels).map(value => (
<div>
<img
src={`https://cdn.hd-plus.de/senderlogos/bright-cropped/${value["groupID"]}.png`}
alt=""
/>
</div>
))}
</div>
</section>
<section className="item-center">
{
Object.values(shows.result).map(value => (
<div className="shows">{
<div className="grid-items">
<div className="item">
<small>{value.startime}</small>
<small>value.resolution</small>
</div>
<div className="item-name">{value.title}</div>
</div>
}
</div>))}
</section>
</div>
</Fragment>
);
}
}
export default Contents;
I need some help with aligning the channels with their respective stations. I hope this is descriptive enough. Thank you
Updated Code for the tiles
<section className="item-center">
{
Object.values(station.result.channels).map(value => (
<div className="shows">{
shows.result.find(show => show['channelID'] === value['groupID']).map(item => (
<div className="grid-items">
<div className="item">
<small>{item.startime}</small>
<small>value.resolution</small>
</div>
<div className="item-name">{item.title}</div>
</div>
))}
</div>))}
</section>
error message
when I try to add Object.values() around it I get this
The correct solution for this (as found in the comments) is to use the filter() function. a find() function would only give back one object, or undefined, so you cannot use map on it.
shows.result.filter(show => show['channelID'] === value['groupID']).map(item =>
())
This will return every object where the channelID equals the groupID, which you can then map to a ui element.
https://www.w3schools.com/jsref/jsref_filter.asp

How to iterate through JSON data and dynamically create and populate components in React?

I'm new to React and JSX and have created a component which displays a title and image which will serve all as a link. I would now like to set the title and image by iterating through JSON data (currently my JSON is accessible via a locally defined variable).
I would like to know how to dynamically create and populate the components with the appropriate data. My code currently looks like this:
<script>
var RecipeList = React.createClass({
const items = [
{
id: 2234567,
title: "Fried Chicken",
image-url: "https://images.media-allrecipes.com/userphotos/560x315/4577069.jpg",
ingredient: ["Chicken", "Flour", "Eggs", "Salt", "Pepper"]
},
{
id: 2234567,
title: "Grilled Chicken",
image-url: "https://images.media-allrecipes.com/userphotos/560x315/4577069.jpg",
ingredient: ["Chicken", "Olive oil", "Salt", "Pepper"]
}
]
getDefaultProps: function() {
return {items: []}
},
render: function() {
var listItems = this.props.items.map(function(item) {
return(
<div className="container-fluid">
<div className="row">
<div className="recipeContainer col-sm-12 col-md-6 col-lg-4">
<h3 className="recipeTitle">{this.props.title}</h3>
<div className="recipeImage">
<img src="{this.props.image}" />
</div>
<div className="recipeBtn">See recipe</div>
</div>
</div>
</div>
);
});
return (
{listItems}
);
}
});
ReactDOM.render(
<div>
<IngredientList></IngredientList>
<RecipeList items={items}></RecipeList>
<RecipeSection></RecipeSection>
</div>
, document.getElementById("module"));
</script>
This can be achieved by passing the JSON data into the items prop of your <RecipeList /> so that this data is used to dynamically render the component via that data.
Additionally, there are a few other things to update to get this to work:
you'll want to fix the format of your input JSON so that item keys are either wrapped with quotes, or don't have hyphens.
ensure you're accessing data from the item in map() when rendering the list items, rather than accessing the item data from this
wrap the list items that you're rendering with a "root element" at the return line of your render() method. A simple solution is to usually wrap the return result with a <div>, however with more recent versions of React you can use <React.Fragment> (this allows you to return multiple elements in a render() result, without adding the extra "div element" to be resulting DOM).
Here's a working snippet:
<div id="module"></div>
<script src="https://unpkg.com/react#16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js" crossorigin></script>
<script type="text/babel">
/*
Use class to define component using React16
*/
class RecipeList extends React.Component {
render() {
var listItems = this.props.items.map(function(item) {
return(
<div className="container-fluid">
<div className="row">
<div className="recipeContainer col-sm-12 col-md-6 col-lg-4">
<h3 className="recipeTitle">{item.title}</h3> { /* <-- Corrected this to use item.title */ }
<div className="recipeImage">
<img src={item.image} /> { /* <-- Corrected this to use item.image */ }
</div>
<div className="recipeBtn">See recipe</div>
</div>
</div>
</div>
);
});
/*
When rendering multiple DOM elements as a list, you
must wrap these with React.Fragment, or something else
like a div
*/
return (<React.Fragment>{listItems}</React.Fragment>);
}
};
/*
Declare items data array which will passed to the items
prop of the <RecipeList> component
*/
const items = [{
'id': 2234567,
'title': "Fried Chicken",
'image': "https://images.media-allrecipes.com/userphotos/560x315/4577069.jpg",
'ingredient': ['Chicken', 'Olive oil', 'Salt', 'Pepper']
},
{
'id': 2234567,
'title': "Grilled Chicken",
'image': "https://images.media-allrecipes.com/userphotos/560x315/4577069.jpg",
'ingredient': ['Chicken', 'Olive oil', 'Salt', 'Pepper']
}];
ReactDOM.render(
<div>
{ /* Pass the items data array to the items prop */ }
<RecipeList items={items}></RecipeList>
</div>,
document.getElementById("module"));
</script>
Hope that helps!

onClick event can't find function in react mapped object

While looping over an object using map() React can't find its own classes property!
Here is the class of the component,
import React, { Component } from 'react';
import './videolists.css';
export default class VideoLists extends Component {
constructor() {
super();
}
getDefaultLists() {
return [
{
title: 'Iridescent (Official Video) - Linkin Park',
url: 'https://www.youtube.com/watch?v=xLYiIBCN9ec',
id: 'xLYiIBCN9ec'
},
{
title: 'Ed Sheeran - I\'m A Mess (x Acoustic Sessions)',
url: 'https://www.youtube.com/watch?v=-t2CR9qZRj0',
id: '-t2CR9qZRj0'
},
{
title: 'Ed Sheeran - Lego House [Official Video]',
url: 'https://www.youtube.com/watch?v=c4BLVznuWnU',
id: 'c4BLVznuWnU'
}
]
}
itemSelected(itemObject) {
console.log(itemObject);
}
render() {
return (
<div>
<div className='panel panel-default'>
<div className='panel-heading'>
<ul className='list-group'>
{this.getDefaultLists().map(function(item, index){
return <li
key = { index }
className='list-group-item'
onClick={ this.itemSelected.bind(this) }>
{ item.title } <br/>
<small className='listurl'>{ item.url }</small>
</li>;
})}
</ul>
</div>
</div>
</div>
);
}
}
When a user would click on an item it should call the function called itemSelected and also binding the current this element with this.
But when the application is throughing and error.
Here is the error message:
Uncaught TypeError: Cannot read property 'itemSelected' of undefined(…)
How I can call this function in this case from the loop?
you are losing the this context because of your map function. not only do you need to bind that, to get the data object sent though you need to actually tell it to do that. like this.
<ul className='list-group'>
{this.getDefaultLists().map( (item, index) => {
return (
<li key ={index} className='list-group-item' onClick={() => this.itemSelected(item)}>
{ item.title }
<br/>
<small className='listurl'>{ item.url }</small>
</li>
);
})}
</ul>
you can try shadowing your this context, shouldn't be necessary, but worth a shot.
const self = this;
...
<ul className='list-group'>
{self.getDefaultLists().map( (item, index) => {
return (
<li key ={index} className='list-group-item' onClick={() => self.itemSelected(item)}>
{ item.title }
<br/>
<small className='listurl'>{ item.url }</small>
</li>
);
})}
</ul>

Categories