Failed prop type: Material-UI: Either `children`, `image`, `src` or `component` prop must be specified - javascript

I kept getting this error even though I have an image prop in CardMedia
Code
Error description
This is a snippet of the code.
const Post = ({ post, setter }) => {
const classes = useStyles();
return(
<Card className={classes.card}>
<CardMedia className={classes.media} image={post.selectedFile} title={post.title} />
<div className={classes.overlay}>
<Typography variant='h6' >{post.creator}</Typography>
<Typography variant='body2' >{moment(post.createdAt).fromNow()}</Typography>
</div>
<div className={classes.overlay2}>
<Button style={{color:'white'}} size='small' onClick={() => setter(post._id)}>
<MoreHorizIcon fontSize='medium' />
</Button>
</div>
<div className={classes.details}>
<Typography variant='body2' color='textSecondary' >{post.tags.map((tag) => `#${tag} `)}</Typography>
</div>
<Typography className={classes.title} variant='h5' gutterBottom>{post.title}</Typography>
<CardContent>
<Typography variant='h5' gutterBottom>{post.message}</Typography>
</CardContent>
<CardActions>
<Button size='small' color='primary' onClick={() => {}}>
<ThumbUpAltIcon fontSize='small' />
like
{post.likeCount}
</Button>
<Button size='small' color='primary' onClick={() => {}}>
<DeleteIcon fontSize='small' />
Delete
</Button>
</CardActions>
</Card>
);
}
I'm new to full stack dev and am following a tutorial by JSMastery which has so far been good. I got this error and im confused. It might be a simple fix but I dont know what information you guys would need to resolve it so please comment if you need more info.

I guess the only reason for this is that provided media is either null or undefined

Related

Not able to see the updated values in react after creating a group

I am trying to perform a simple exercise, wherein I am showing the data from the local JSON file saved in my folder, and then reading it to show the data with useState, such that when a user clicks in he can edit the author and location filed and save it.
The issue I get is when I save the data in my group or location it does not populate the new value, however, it just removes the new value, but when I filter and select all values from the dropdown I can see the values in there.
Can anyone please let me know what is the missing part here? I want to achieve the task that when a user updates the value on the author group or location group they should be there with the new group value.
Please the link to the code below and a working demo on codeSandbox
watch the full code and demo here
The source code for the author group component I tried so far;
import { useEffect, useState } from "react";
import {
Container,
Accordion,
AccordionSummary,
AccordionDetails,
Typography,
Button
} from "#mui/material";
import ExpandMoreIcon from "#mui/icons-material/ExpandMore";
import EditIcon from "#mui/icons-material/Edit";
const Authorsgroup = ({
posts,
groupDropdownValue,
setShowForm,
setPostId,
showForm
}) => {
const authorGroup = posts.reduce((group, authorgroup) => {
(group[authorgroup.author.replace(/ +/g, "")] =
group[authorgroup.author.replace(/ +/g, "")] || []).push(authorgroup);
return group;
}, {});
const [authorGroupValues, setAuthorGroupValues] = useState(authorGroup);
useEffect(() => {
setAuthorGroupValues(authorGroup);
console.log(authorGroupValues);
}, [groupDropdownValue, showForm]);
return (
<>
{/* all gorupby authors */}
<Container>
{/* show group of Tapesh */}
<Container style={{ marginTop: "3rem" }}>
{authorGroupValues?.Tapesh.map((post, index) => (
<Accordion key={index}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography variant="h6" style={{ color: "#EB1283" }}>
{post.id} {post.author} {post.location}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant="h4">{post.location}</Typography>
<Typography>{post.text}</Typography>
<Button
variant="outlined"
onClick={() => {
setShowForm(!showForm);
setPostId(post.id);
}}
startIcon={<EditIcon />}
>
Edit
</Button>
</AccordionDetails>
</Accordion>
))}
</Container>
{/* show group of HappyManager */}
<Container style={{ marginTop: "3rem" }}>
{authorGroupValues?.HappyManager.map((post, index) => (
<Accordion key={index}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography variant="h6" style={{ color: "orange" }}>
{post.id} {post.author} {post.location}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant="h4">{post.location}</Typography>
<Typography>{post.text}</Typography>
<Button
variant="outlined"
onClick={() => {
setShowForm(!showForm);
setPostId(post.id);
}}
startIcon={<EditIcon />}
>
Edit
</Button>
</AccordionDetails>
</Accordion>
))}
</Container>
{/* show group of HappyDeveloper */}
<Container style={{ marginTop: "3rem" }}>
{authorGroupValues?.HappyDeveloper.map((post, index) => (
<Accordion key={index}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography variant="h6" style={{ color: "green" }}>
{post.id} {post.author} {post.location}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant="h4">{post.location}</Typography>
<Typography>{post.text}</Typography>
<Button
variant="outlined"
onClick={() => {
setShowForm(!showForm);
setPostId(post.id);
}}
startIcon={<EditIcon />}
>
Edit
</Button>
</AccordionDetails>
</Accordion>
))}
</Container>
{/* show group of HappyUser */}
<Container style={{ marginTop: "3rem" }}>
{authorGroupValues?.HappyUser.map((post, index) => (
<Accordion key={index}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography variant="h6" style={{ color: "red" }}>
{post.id} {post.author} {post.location}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant="h4">{post.location}</Typography>
<Typography>{post.text}</Typography>
<Button
variant="outlined"
onClick={() => {
setShowForm(!showForm);
setPostId(post.id);
}}
startIcon={<EditIcon />}
>
Edit
</Button>
</AccordionDetails>
</Accordion>
))}
</Container>
</Container>
</>
);
};
export default Authorsgroup;
Thanks any suggestions or help are really appreciated.

React - Material UI Menu not working properly

I'm using the menu/menu item from material ui. It seems to have an issue if I try to render it based on a condition. Refer below...
const AddSelectItemButton = () => {
return (
<>
<Fab
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleClick}
className={classes.addButton}
size="medium"
color="primary"
aria-label="add"
>
<AddIcon />
</Fab>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleDelete}>Delete Item</MenuItem>
<MenuItem onClick={handleAddNew}>Add Item</MenuItem>
</Menu>
</>
)
}
Inside the main container I have something like this
return (
<div className='my-5'>
<Paper className="pl-5 pr-5 pb-5 position-relative">
<Typography className="pt-4 mb-4 text-center" variant="h4">My Items</Typography>
{!isAuthMode &&
<AddSelectItemButton />
}
<Grid container spacing={3} justify="center">
{allItems.items.map(item=>
<Grid key={item.id} item xs={5} className={`mt-4`} style={{height: '200px'}}>
<Card className={`${classes.root} d-flex ${classes.packInner}`}>
<CardActionArea className="d-flex">
<CardMedia
className={`${classes.media} ${classes.cardImage}`}
image={item.image}
title={item.brand}
/>
<CardContent className={classes.textContainer}>
<Typography gutterBottom variant="subtitle1">
{item.brand}
</Typography>
<Typography variant="body2" color="textSecondary">
{item.name}
</Typography>
<Typography variant="body2" color="textSecondary">
Weight: {item.weight}
</Typography>
<Typography variant="body2" color="textSecondary" className={classes.itemDescription}>
{packInfo.description.length > 80 ?
(`${packInfo.description.substring(0, 77) + '...'}`)
:
packInfo.description
}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
)}
</Grid>
</Paper>
</div>
);
If I don't do the condition and include the code in the original rendering. The menu loads at the position of the button. With the condition, it renders far top left of the page and not at the button.
Anyone have an idea or need more info?
Thanks!
{!isAuthMode && (
<AddSelectItemButton />
)}

Open only one dropdown in within an array of cards

I have an array of news that I'm displaying through Material-ui components, while mapping over it when I click on one dropdown to show more from the description, all the cards opens up instead of only the one I clicked on. I would like to avoid this behaviour. If you can answer my question it will be appreciated. The code is this
{Articles.map((article, index) => {
return (
<>
<Grid item xs={12} sm={6}>
<Card key={index} className={classes.root}>
<CardHeader
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title={article.title}
subheader={new Date(article.publishedAt).toLocaleString(
"it-IT",
options
)}
/>
<CardMedia
className={classes.media}
image={article.urlToImage}
title={article.title}
/>
<CardContent>
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{article.description}
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon />
</IconButton>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
<IconButton
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="scopri di piu"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>{article.content}</Typography>
<Typography>
Per leggere l'intero articolo clicca{" "}
<a
href=""
target="_blank"
rel="noreferrer noopener canonical"
>
qui
</a>
</Typography>
</CardContent>
</Collapse>
</Card>
<br />
<br />
<br />
</Grid>
</>
)
})}
</Grid>
The handleExpandClick function
const [expanded, setExpanded] = useState(false)
const handleExpandClick = () => {
setExpanded(!expanded)
}

How to edit content of Material UI Card

I am displaying few details in Material UI card and have an 'Edit' button. On click of Edit button, i need to update the card content within the same Card layout. Here is the code
<Card className={classes.root} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={click}>
Edit
</Button>
</CardActions>
</Card>
CodeSandbox
How to get the edit functionality working?
const [editing, setEditing] = useState(false);
return (
<Card className={classes.root} variant="outlined">
<CardContent>
{ editing ? (
<textarea>
editing
</textarea>
) : (
<div>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</div>
)}
</CardContent>
<CardActions>
<Button size="small" onClick={() => setEditing(true)}>
Edit
</Button>
</CardActions>
</Card>
);
Not the same layout, however, you can provide editable view of the same layout in this way depending on the editing state.
I think is better to use Input fields instead of Typography components. I've put an example here.
When you click in edit, the input fields are editable and when it loses focus it is blocked for editing:
// all imports here
const useStyles = makeStyles({
[...]
});
export default function OutlinedCard() {
const [isEditable, setIsEditable] = useState(false);
const [name, setName] = useState("");
const classes = useStyles();
const handleEdit = () => {
console.log("I am here");
setIsEditable(!isEditable);
};
return (
<Card className={classes.root} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<TextField
id="standard-basic"
label="Name:"
disabled={!isEditable}
value={name}
onChange={(e) => setName(e.target.value)}
onBlur={() => setIsEditable(false)}
/>
</CardContent>
<CardActions>
<Button size="small" onClick={handleEdit}>
Edit
</Button>
</CardActions>
</Card>
);
}

How can I pass data from one card, in a list of cards, to a dialog?

I want to add a confirmation step for my CRUD application using a Material-UI dialog, but I don't seem to be able to pass any data to my dialog.
I have a list/grid of cards that I've created using .map(), each of which contains data I pulled from a MongoDB document. I'm able to delete the documents/cards from my app with just a button, but now I'd like to add a confirmation step to the deletion process, using a Material-UI dialog. To do that, I need to pass data from the cards to the dialog (if that's the correct phrasing for what I'm trying to do). I can't figure out how to do that.
I've tried passing the data using this.props.match.params.id, this.id, this._id, this.oneSavedArticle.id, and this.props.oneSavedArticle.id, but they all have either returned an error or undefined.
Here is my delete function:
handleDelete = id => {
console.log(id);
API.deleteArticle(this)
.then(res => console.log(res.data))
.catch(err => console.log(err));
// this.props.history.push("/saved");
};
Here is my dialog:
<div>
<Button
color="secondary"
variant="outlined"
onClick={this.handleClickOpen}
>
DELETE
</Button>
<Dialog
open={this.state.open}
TransitionComponent={Transition}
keepMounted
onClose={this.handleClose}
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description"
>
<DialogTitle>
{"Delete this article?"}
</DialogTitle>
<Divider variant="middle" />
<DialogActions>
<Button onClick={this.handleClose} color="secondary">
NO
</Button>
<Button
onClick={() => this.handleDelete(this.props)}
color="primary"
>
YES
</Button>
</DialogActions>
</Dialog>
</div>
Here is my API route:
deleteArticle: function(id) {
return axios.delete("/api/articles/" + id);
}
Here is where and how I've implemented the dialog into my list of cards:
{this.state.savedArticles.length ? (
<Grid>
{this.state.savedArticles.map((oneSavedArticle, i) => (
<Card style={savedArticleCard} key={i}>
<Typography variant="h5">{oneSavedArticle.headline}</Typography>
<Divider variant="middle" />
<Typography>{oneSavedArticle.snippet}</Typography>
<a href={oneSavedArticle.web_url} style={linkStyles}>
<Button style={buttonStyles}>READ IT</Button>
</a>
<DeleteDialogue {...this.props} />
</Card>
))}
</Grid>
As you can expect, I'd just like to be able to pass the data from to card to the dialog so I can get my delete function functioning correctly.
If I've left out any info, or haven't provided enough code, or haven't explained something clearly enough, please let me know.
Many thanks ahead of time!
If I understand correctly, the DeleteDialogue is the dialog component that you are talking about.
If so, try passing a specific prop to the dialog and use it in the dialog.
Something like that:
{this.state.savedArticles.length ? (
<Grid>
{this.state.savedArticles.map((oneSavedArticle, i) => (
<Card style={savedArticleCard} key={i}>
<Typography variant="h5">{oneSavedArticle.headline}</Typography>
<Divider variant="middle" />
<Typography>{oneSavedArticle.snippet}</Typography>
<a href={oneSavedArticle.web_url} style={linkStyles}>
<Button style={buttonStyles}>READ IT</Button>
</a>
<DeleteDialogue id={oneSavedArticle.id} />
</Card>
))}
</Grid>
And in the dialog:
<div>
<Button
color="secondary"
variant="outlined"
onClick={this.handleClickOpen}
>
DELETE
</Button>
<Dialog
open={this.state.open}
TransitionComponent={Transition}
keepMounted
onClose={this.handleClose}
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description"
>
<DialogTitle>
{"Delete this article?"}
</DialogTitle>
<Divider variant="middle" />
<DialogActions>
<Button onClick={this.handleClose} color="secondary">
NO
</Button>
<Button
onClick={() => this.handleDelete(this.props.id)}
color="primary"
>
YES
</Button>
</DialogActions>
</Dialog>
</div>
I think its suppose to work that way..

Categories