I'm trying to get my React CardImg to render with no luck. I'm importing the photos array, passing it in state, and trying to render it on line's 40 CardImg component. I've tried changing the file paths with no luck. Any help would be appreciated. Images folder is inside the public folder.
import React, { Component } from 'react';
import { CardTitle, Jumbotron, Card, CardBody, CardHeader, CardImg, Button, Modal, ModalHeader, ModalBody, Form, FormGroup, Input, Label, Col, Row, InputGroup, CardSubtitle, CardImgOverlay } from 'reactstrap';
import DatePicker from "react-datepicker";
import { PHOTOS } from '../shared/photos';
import "react-datepicker/dist/react-datepicker.css";
class Home extends Component {
constructor(props) {
super(props);
this.state = {
isModalOpen: false,
photos: PHOTOS,
};
this.toggleModal = this.toggleModal.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(values) {
this.props.postQuery(values);
};
toggleModal() {
this.setState({
isModalOpen: !this.state.isModalOpen
});
}
render() {
return (
<React.Fragment>
<Jumbotron id="homePage"></Jumbotron>
<div className="container">
<div className="row">
<div className="col-sm-6">
<h1>Maximum Experience</h1>
<h2>Minimum Weight</h2>
</div>
<div className="col-sm-6">
<Card>
<CardImg src={this.state.photos.image} width='100%' alt="Hiking" />
</Card>
</div>
</div>
photos.js
export const PHOTOS = [
{
id: 0,
name: 'Card Home Image',
image: 'images/homeCard.jpg',
}
]
Your this.state.photos is an array. So you need {this.state.photos[0].image}.
When you have more than one photo objects in the array you need to iterate over it to render all photos, something like
{
this.state.photos.map(photo => (
<Card>
<CardImg src={photo.image} width='100%' alt="Hiking" />
</Card>
)
}
Related
I'm trying to open a modal dialog from a set of cards that has been looping from the data the component receives. I can't figure it out how to make the modal get the appropriate data from the clicked card. In my code below, I tried to put the modal outside the loop, but then I can't figure it out how to pass the id of the clicked card to a new function which would control the modal
Here is the Component that manages the cards loop and contains the modal
import React, {Component} from 'react';
import {Nav, NavItem, NavLink, Card, CardImg, CardText,
CardBody, CardTitle, CardSubtitle, FormGroup, Input, Col, Button, Modal, ModalHeader, ModalBody} from 'reactstrap';
import classnames from 'classnames';
class ProductCard extends Component {
constructor(props){
super(props);
this.state={
productList: this.props.products,
isModalOpen: false
}
this.toggleModal = this.toggleModal.bind(this)
}
toggleModal() {
this.setState({
isModalOpen: !this.state.isModalOpen
});
}
render(){
return(
this.state.productList.map(prod => (
<div key={prod.prod_id} className="col-12 col-md-3 mb-4 rowCard" onClick={this.toggleModal}>
<Card>
<CardImg top width="100%" src={prod.prod_image} alt={prod.prod_name_eng}/>
<CardBody>
<CardTitle>{prod.prod_name_eng}</CardTitle>
<CardSubtitle>{prod.prod_cost_total}</CardSubtitle>
<CardText>{prod.prod_description}</CardText>
</CardBody>
</Card>
<Modal isOpen={this.state.isModalOpen} toggle={this.toggleModal}>
<ModalHeader toggle={this.toggleModal}>{prod.prod_name_eng}</ModalHeader>
<ModalBody>{prod.prod_description}</ModalBody>
</Modal>
</div>
))
);
}
}
Any help is welcome! thanks
I would suggest moving the Modal outside of your map, since that makes things more complicated than they need to be. If you do this, then you toggleModal method is then responsible for accepting an index (supplied by the map function) and then you would just need to retrieve the correct text for the modal elements.
toggleModal(index) {
this.setState({
cardIndex: index,
isModalOpen: !this.state.isModalOpen
});
}
Then you're modal just needs to reference the productList in state, access the index and get the title and description:
class ProductCard extends Component {
constructor(props) {
super(props);
this.state = {
productList: this.props.products,
cardIndex: null,
isModalOpen: false
};
this.toggleModal = this.toggleModal.bind(this);
}
toggleModal(id) {
console.log(id);
this.setState({
cardIndex: id,
isModalOpen: !this.state.isModalOpen
});
}
render() {
const { productList, cardIndex } = this.state;
console.log("CardIndex: ", cardIndex);
console.log("Product: ", productList[cardIndex]);
return (
<Fragment>
{productList.map((prod, index) => {
return (
<div
key={prod.prod_id}
className="col-12 col-md-3 mb-4 rowCard"
onClick={e => this.toggleModal(index)}
>
<Card>
<CardImg top src={prod.prod_image} alt={prod.prod_name_eng} />
<CardBody>
<CardTitle>{prod.prod_name_eng}</CardTitle>
<CardSubtitle>{prod.prod_cost_total}</CardSubtitle>
<CardText>{prod.prod_description}</CardText>
</CardBody>
</Card>
</div>
);
})}
<Modal
isOpen={this.state.isModalOpen}
toggle={e => this.toggleModal(cardIndex)}
>
<ModalHeader toggle={e => this.toggleModal(cardIndex)}>
{cardIndex !== null && productList[cardIndex].prod_name_eng}
</ModalHeader>
<ModalBody>
{cardIndex !== null && productList[cardIndex].prod_description}
</ModalBody>
</Modal>
</Fragment>
);
}
}
Here is a codesandbox link to a working version:
I have 2 class components in 2 different js files. The "dish" variable is defined in one and I'm trying to use it in the second file. I'm still new to this, so I'm really not sure if I'm structuring this correctly. Could some one help?
First class component
import React, { Component } from "react";
import {
Card,
CardImg,
CardImgOverlay,
CardText,
CardBody,
CardTitle
} from "reactstrap";
import Dishdetail from "./DishdetailComponent";
class Menu extends Component {
constructor(props) {
super(props);
this.state = {
selectedDish: null,
details: Dishdetail
};
}
onDishSelect(dish) {
this.setState({
selectedDish: dish
});
}
renderDish(dish) {
if (dish != null) {
return <Dishdetail details={this.state.details} />;
} else {
return <div />;
}
}
render() {
const menu = this.props.dishes.map(dish => {
return (
<div className="col-12 col-md-5 m-1">
<Card key={dish.id} onClick={() => this.onDishSelect(dish)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle> {dish.name} </CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return (
<div className="container">
<div className="row"> {menu}</div>
<div className="row">
<div className="col-12 col-md-5 m-1">
{this.renderDish(this.state.selectedDish)}{" "}
</div>{" "}
</div>{" "}
</div>
);
}
}
export default Menu;
=======================
Second code
import React, { Component } from "react";
import {
Card,
CardImg,
CardImgOverlay,
CardText,
CardBody,
CardTitle
} from "reactstrap";
import Menu from "./MenuComponent";
class Dishdetail extends Component {
constructor(props) {
super(props);
this.state = {
dish: Menu
};
}
render() {
return (
<div className="container">
<div className="row">
<dish />
<Card>
<CardImg top src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle>{dish.name}</CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
</div>
</div>
);
}
}
export default Dishdetail;
The error message I'm getting is that "dish" variable is not defined
You cannot set props to state in child like this,
this.state = {
dish: Menu
};
As you are passing details as props from parent component you should do this,
constructor(props) {
super(props)
this.state = {
dish: props.details,
}
}
And you should use this state in child component like.
{this.state.dish}
Demo - How to pass data from parent and usage in child component.
Update
Your Code - I have corrected your code. Just make sure you pass correct details to your Menu component.
Note: This code gives you error because I don't know what this.props.dishes is. Ignore the error and concentrate on code only.
When I try to compile my code, I get the error:
Error Image
I was following a tutorial and the only difference is the name of each column/field in Airtable. My project should be working but it isn't. Did I forget to declare something in particular? Is there an easier way to get images from Airtable? React Airtable Tutorial
import React, { Component } from 'react';
import { Container, Row, Col, Card, CardImg, CardText, CardBody,
CardTitle, CardSubtitle, Button } from 'reactstrap';
import './main.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
skills: [],
};
}
componentDidMount() {
fetch('https://api.airtable.com/v0/appXy4JgrvUicfB5F/Resources?api_key=keyE0exOkvaAnJeS0')
.then((resp) => resp.json())
.then(data => {
console.log(data);
this.setState({ skills: data.records });
}).catch(err => {
// Error 🙁
});
}
render() {
return (
<div className="container">
<Row>
<Col>
{this.state.skills.map(skill => <Roster {...skill.fields} /> )}
</Col>
</Row>
</div>
);
}
}
export default App;
const Roster = ({ Name, Service, LinkedIN, GitHub, Twitter, Facebook, Picture }) => (
<div className="card">
<div className="card-body">
<img className="card-img-left" src={Picture[0].url} />
<h5 className="card-title">{Name}</h5>
<p className="card-subtitle">{Service}</p>
<p className="card-text">
<small className="text-muted"></i></small>
<small className="text-muted"></i></small>
<small className="text-muted"></i></small>
<small className="text-muted"></i></small>
</p>
</div>
</div>
);
The Airtable API that you are using does not have a Picture property in for lots of objects and they are failing when trying to access Picture[0] because Picture is undefined.
If you do not have images for all objects, the easy way would be check if there is a Picture first before rendering:
{Picture && <img className="card-img-left" src={Picture[0].url} />}
Demo on Stackblitz
I am building a product grid order tool for an e-commerce website. It allows the merchandiser to change the order in which the products display.
This is achieved through drag-and-drop superpowers of Packery by David Desandro https://packery.metafizzy.co/
Seems there are two ways to do this. Either run his code (with jQuery) in a componentDidMount() {}; or find a React version of Packery, like https://www.npmjs.com/package/react-packery-component . There are a number of these but all present a similar problem. Their examples call the object differently. (Mine has curly braces). And I am getting a frightening TypeError!
TypeError: Cannot read property 'bool' of undefined
import React, { Component } from 'react'
import {
Card,
CardImg,
CardBody,
CardTitle,
Input,
InputGroup,
Container,
Row,
// Col,
Jumbotron
} from 'reactstrap';
import Papa from 'papaparse'
import 'bootstrap/dist/css/bootstrap.min.css'
import './App.css'
import Packery from 'react-packery-component'
class App extends Component {
constructor(props) {
super(props);
this.state = {data: [] }; // State holds gridorder / neworder
this.handleChange = this.handleChange.bind(this);
this.updateData = this.updateData.bind(this)
}
handleChange(event) {
event.preventDefault()
const inventory = event.target.files[0]
Papa.parse(inventory, {
header: true,
complete: this.updateData
})
} // END
updateData(results) {
const data = results.data
console.log(data)
this.setState({data}) // {data:data}
}
renderData() {
return this.state.data.length > 1
? this.state.data.map((item) => ( // Object in return
<Card className="grid-item" key={item.sku} >
<CardImg src={item.image} />
<CardTitle> {item.sku} </CardTitle>
<CardBody> {item.name} </CardBody>
</Card>
))
: null
}
render() {
return (
<div>
<Jumbotron>
<form >
<InputGroup>
Name:
<Input type="file" onChange={this.handleChange} />
</InputGroup>
</form>
</Jumbotron>
<div className="album">
<Container>
{/* This throws a TypeError. NOTE: I am calling renderData() */}
<Packery className="grid" > {this.renderData()} </Packery>
</Container>
</div>
</div>
);
}
} // END
export default App
The reason I am keeping the object in state is because, that is the thing that will change. gridorder in, neworder out. Thank you in advance, for I could sure use the help.
I am trying to implement Presentational and Container Components using probs, but I get this error "Cannot read property 'image' of undefined" while trying to access an item passed using props.Below is the code I am using in order of Heirachy.The last class(DishDetail.js) has the problem
App.js
import React, { Component } from 'react';
import Main from './components/MainComponent.js';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<Main />
</div>
);
}
}
export default App;
MainComponent.js
import React, { Component } from 'react';
import { Navbar, NavbarBrand } from 'reactstrap';
import { DISHES } from '../shared/dishes';
import Menu from './MenuComponent';
import DishDetail from './DishDetail';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES,
selectedDish: null
};
}
onDishSelect(dishId) {
this.setState({ selectedDish: dishId});
}
render() {
return (
<div>
<Navbar dark color="primary">
<div className="container">
<NavbarBrand href="/">Ristorante Con Fusion</NavbarBrand>
</div>
</Navbar>
<Menu dishes = {this.state.dishes}
onClick={(dishId) => this.onDishSelect(dishId)} />
<DishDetail
dish = {this.state.dishes.filter((dish) => dish.id === this.state.selectedDish)[0]} />
</div>
);
}
}
export default Main;
MenuComponent.js
import React, { Component } from 'react';
import { Card, CardImg, CardImgOverlay, CardText, CardBody, CardTitle } from 'reactstrap';
class Menu extends Component {
constructor(props) {
super(props);
}
render() {
const menu = this.props.dishes.map((dish) => {
return (
<div key={dish.id} className="col-12 col-md-5 m-1">
<Card onClick={(dishId)=>this.props.onClick(dish.id)}>
<CardImg width="100%" src={dish.image} alt={dish.name}/>
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return (
<div className="container">
<div className="row">
{menu}
</div>
</div>
);
}
}
export default Menu;
DishDetail.js
import React, { Component } from 'react';
import { Card, CardImg, CardImgOverlay, CardText, CardBody, CardTitle } from 'reactstrap';
class DishDetail extends Component {
constructor(props) {
super(props);
}
renderComments(comments){
const comment_layout= comments.map((comment)=>{
if(comment.comment!=null){
return(
<div>
<h4>Comment</h4>
{comment.comment}
{comment.author}, {new Intl.DateTimeFormat('en-US',{year:'numeric',month:'short',day:'2-digit'}).format(new Date(Date.parse(comment.date)))}
</div>
);
}else{
return(
<div></div>
);
}
});
return(comment_layout);
}
render() {
return (
<div className="row col-sm-12 col-12 m-1 container">
<div className="col-md-5 col-sm-12">
<Card>
<CardImg top src={this.props.dish.image} alt={this.props.dish.name}/>
<CardBody>
<CardTitle>{this.props.dish.name}</CardTitle>
<CardText>{this.props.dish.description}</CardText>
</CardBody>
</Card>
</div>
<div className="col-md-5 col-sm-12 m-1">
{this.renderComments(this.props.dish.comments)}
</div>
</div>
);
}
}
export default DishDetail;