i have a cards.js which has the following function. Now the calling method passes three values . header1, header2 and Link (this is the *.js page that has to be called)
export default function Cards(props) {
const classes = useStyles();
return (
<div className="App">
<Card className={classes.card} variant="outlined">
<CardContent>
<Typography
variant={"h5"}
gutterBottom
>
{props.header1}
</Typography>
<Typography
variant={"caption"} >
{props.header2}
</Typography>
<Divider className={classes.divider} light />
<Button variant="contained" color="secondary" onClick={()=> (call either link1.js or link2.js )}>
Lets goooooo!
</Button>
</CardContent>
</Card>
</div>
);
}```
calling method
class UIM extends Component {
render() {
return (
<div className="text-page">
<Grid container alignItems="center" justify="space-evenly" >
<Grid ><Cards header1="card 1 for a task1" header2="click text2" link="link1"/></Grid>
<Grid ><Cards header1=" card 2 for task 2" header2=" click text 2" link="link2"/></Grid>
</Grid>
</div>
)
}
}
I am new to react and learning right now, so wondering if such a thing is possible or should i use router to route to different pages (ie. call either link1.js or link2.js ) ??
I found out by by adding pathname:props.link i can get the button to link to multiple locations within the material ui button.
<Card className={classes.card} variant="outlined">
<CardContent>
<Typography
variant={"h5"}
gutterBottom
>
{props.header1}
</Typography>
<Typography
variant={"caption"} >
{props.header2}
</Typography>
<Divider className={classes.divider} light />
<Button variant="contained" color="secondary">
<NavLink to={{pathname:props.link}}>Lets goooooo!</NavLink>
</Button>
</CardContent>
</Card>
Related
I have three components im trying to connect together to add the number of items I have in a shopping cart. I have the main component which creates the CartCount object and setCartCount functionality:
function MinerStore() {
const [cartCount, setCartCount] = useState([0]);
const addToCart = () => {
setCartCount(cartCount + 1);
};
return (
<>
<div >
<StoreNav cartCount={cartCount} />
<div>
<StoreCard addToCart={addToCart} />
</div>
</div>
</>
);
}
I also then have the two components I am trying to show the added count on as well as the added count functionality:
export default function StoreCard(addToCart) {
return (
<ThemeProvider theme={theme}>
<main>
<Container>
<Grid container spacing={3}>
{data.map((data) => (
<Grid item key={data.id} xs={12} sm={6} md={3}>
<Card>
<CardContent>
</CardContent>
<CardActions>
<div>
<Button onClick={addToCart}>
Add to Cart
</Button>
</div>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
</ThemeProvider>
);
}
export default function StoreNav(cartCount) {
return (
<AppBar position="static">
<Toolbar>
<IconButton>
<Badge badgeContent={cartCount} color="primary">
<ShoppingCartIcon />
</Badge>
</IconButton>
</Toolbar>
</AppBar>
);
}
You've set your initial state as an array [0].
Set it as as 0 and check it out
And ofc as the people above mentioned you should either use props or {addToCart} in the child's parameter.
Then on button should look as such:
<Button onClick={addToCart /* or props.addToCart */}>Add to Cart </Button>
How can I make the state in the added forms work independently of changes in other similar forms?
Forms are added through locationAdd
const LocationBody = ({filteredServersData, locationAdd,
deleteLocationCell, handleChangeFilter,
filters, locationsData, envsData }) => {
const classes = useStyles();
const locationsSelect = locationsData.map((item) => {
return <MenuItem key={item.locationID} value={item.locationID}>{item.name}</MenuItem>;
})
const envsSelect = envsData.map((item, index) => {
return <MenuItem key={index} value={item.envID}>{item.name}</MenuItem>;
})
const serversSelect = filteredServersData.map(item => <Typography variant="h6" component="h1">
{item.name}
</Typography>)
return (
<div>
{locationAdd.map(i => <Container className={classes.root} key={i.id}>
<Grid container spacing={3} className="arr">
<Grid item xs={12}>
<Box display="flex" justifyContent="space-between">
<Typography variant="h5" component="h1">
Тестовая локация {i.id}
</Typography>
<IconButton
aria-label="delete" color="secondary"
className={classes.margin}
onClick={() => deleteLocationCell(i)}>
<DeleteIcon fontSize="medium" />
</IconButton>
</Box>
</Grid>
<Grid item xs={12} className={classes.filtersContainer}>
<Box display="flex" justifyContent="space-between">
<Box display="flex" className={classes.fieldsContainer}>
<Typography variant="h6" component="h1">
Локация
</Typography>
<FormControl variant="outlined">
<Select
value={filters.locationID}
onChange={handleChangeFilter}
label="LocationID"
labelId="locationID"
name="locationID"
>
{locationsSelect}
</Select>
</FormControl>
<FormControl variant="outlined">
<Select
value={filters.envID}
onChange={handleChangeFilter}
label="EnvID"
labelId="envID"
name="envID" >
{envsSelect}
</Select>
</FormControl>
{serversSelect}
</Box>
</Box>
</Grid>
</Grid>
</Container>)}
</div>
)
}
You can create a new component for added forms and each component will handle its own state only, without sharing it with other siblings.
Or, if you don't want to create a new component, and want to keep the current code as it is, you may differentiate each form's state by prefixing it with the form's unique ID.
I’m having an issue with React and using the material-ui library. My cards are getting rendered vertically instead of side by side horizontally. I tried messing around with the react grid component but it didn’t help.
Output:
Expected:
Here is the original code that perfectly renders cards side by side: https://github.com/acm-uic/roll-call/blob/feature/home-page/src/App.tsx
return (
<React.Fragment>
<CssBaseline />
<AppBar position="relative">
<Toolbar>
<Typography variant="h6" color="inherit" noWrap>
ACM Roll Call
</Typography>
</Toolbar>
</AppBar>
<main>
{/* Hero unit */}
<div className={classes.heroContent}>
<Container maxWidth="sm">
<Typography component="h1" variant="h2" align="center" color="textPrimary" gutterBottom>
ACM Roll Call
</Typography>
<Typography variant="h5" align="center" color="textSecondary" paragraph>
The Association for Computing Machinery Student Chapter at the University of Illinois at Chicago (ACM#UIC) is a community for all UIC students interested in computing, computing machinery and related technologies.
</Typography>
</Container>
</div>
<Container className={classes.cardGrid} maxWidth="md">
{/* End hero unit */}
<Grid container spacing={4}>
{cards.map(card => (
<Grid item key={card} xs={12} sm={6} md={4}>
<Card className={classes.card} raised>
<CardMedia
className={classes.cardMedia}
image="https://avatars3.githubusercontent.com/u/20177515?s=280&v=4"
title="Image title"
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
Event Name
</Typography>
<Typography>
This is a media card. You can use this section to describe the content.
</Typography>
</CardContent>
<CardActions>
<Button size="small" color="primary">
View
</Button>
<Button size="small" color="primary">
Edit
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
{/* Footer */}
<footer className={classes.footer}>
<Typography variant="h6" align="center" gutterBottom>
ACM Roll Call
</Typography>
<Typography variant="subtitle1" align="center" color="textSecondary" component="p">
Attendance tracking for events and meetings
</Typography>
</footer>
{/* End footer */}
</React.Fragment>
);
I modified the original code since I had to fetch data for the cards. Here is the modified version in two separate files (Event.tsx & Events.tsx): https://github.com/acm-uic/roll-call/tree/feature/printEvents/src/components
return (
<React.Fragment>
<CssBaseline />
<Container className={classes.cardGrid} maxWidth="md">
{/* End hero unit */}
<Grid container spacing={4}>
{cards.map(card => (
<Grid item key={card} xs={12} sm={6} md={4}>
<Card className={classes.card} raised>
<CardMedia
className={classes.cardMedia}
image="https://avatars3.githubusercontent.com/u/20177515?s=280&v=4"
title="Image title"
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant="h5" component="h2">
{summary ? summary : 'Busy'}
</Typography>
<Typography>
<div>
{start ? (start.dateTime ? start.dateTime : start.date) : <></>} | {end ? (end.dateTime ? end.dateTime : end.date) : <></>} | {location}
</div>
</Typography>
</CardContent>
<CardActions>
<Button size="small" color="primary">
View
</Button>
<Button size="small" color="primary">
Edit
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</React.Fragment>
);
You can use MUI's autolayout feature on the Grid to help you customize your card rendering.
import React from 'react';
import { Grid } from '#material-ui/core';
import CardData from 'path to get your data'; // Data must be an array
export default const Main = props => {
return (
<Grid container direction="row" justify="center" alignItems="center" spacing={3}>
{
CardData.map(data => (
<Grid item xs sm md lg key={data.key}>
<CustomCard data={data} />
</Grid>
))
}
</Grid>
);
}
By just providing the property xs, md, sm, lg and xl without the numbering, MUI will do the stacking for you as equally as possible within the same row. So all you need to do is adjusting the size of your card content to allow for several card placement within the same row.
I downloaded your repo and ran it on my machine. It only rendered AppBar so please let me know how to get the data to be displayed. However, I also looked at the code and I noticed one thing.
We are looping through the events and rendering component like so:
{(this.state.events && this.state.events.items)
? this.state.events.items.map((ev, key) =>
(<Event key={key} ev={ev} />)) //render material card for each event
: (<></>)}
But the <Container /> and <Grid /> components are being rendered from <Event /> component. It means that event cards will be contained in its own container and Grid. In my opinion, this is what could be causing the issue.
If we pull container and Grid out of Event.tsx and put in inside Events.tsx then it might fix it.
e.g.,
<Container>
<Grid ..>
this.state.events.items.map((ev, key) =>
(<Event key={key} ev={ev} />)) //render material card for each event
: (<></>)}
</Grid .. />
<Container />
Hello i need to move my grids to display the following layout
However right now my layout looks like this
I am still trying to understand how grid work, below is my attempt at formatting the grid, however it doesn't want to align itself in the manor of which i wish
<Grid item xs={8}>
<Grid className = {classes.root} container direction ="column"
alignItems="flex-start">
{/* <Typography variant="title" style={{ }}>example</Typography> */}
<Paper className = {classes.mainDetailsPaper}>
<Typography variant="title">Main Details</Typography><Divider />
<Typography variant="subheading">Organisation: </Typography>
<Typography variant="subheading">Category: </Typography>
<Typography variant="subheading">Sub Category: </Typography>
</Paper>
</Grid>
<Grid className = {classes.root} container direction ="row"
alignItems="flex-end">
<Paper className = {classes.subDetailsPaper}>
<Typography variant="title">Contract Dates</Typography><Divider />
<Typography variant="subheading">Start Date: </Typography>
</Paper>
<Paper className = {classes.subDetailsPaper}>
<Typography variant="title">Valuation</Typography><Divider />
<Typography variant="subheading">Estimated Contract Value: </Typography>
</Paper>
<Paper className = {classes.subDetailsPaper}>
<Typography variant="title">Supplier Info</Typography><Divider />
</Paper>
</Grid>
</Grid>
I create a functional component and a class component.
In the render method I want to call my functional component as a component prop.
My code:
function projectList(props) {
const { classes } = props
return (
<div>
{projects.slice(0, 5).map(project => (
<Card className={classes.card} key={project.id}>
<CardHeader
classes={{ title: classes.h6, subheader:
classes.subtitle1 }}
title={project.projectName}
subheader={project.h5}
/>
<CardActionArea>
<CardMedia
component="img"
alt={project.h5}
className={classes.media}
image={project.img}
/>
<CardContent>
<Typography paragraph>
{project.paragraph}
</Typography>
</CardContent>
</CardActionArea>
<CardActions className={props.classes.actions}>
<Button
className={props.classes.projectButton}
component={Link}
to={project.pathname}
size="medium"
color="secondary"
>
Project Details
</Button>
</CardActions>
</Card>
))}
</div>
)
}
projectList.propTypes = {
classes: PropTypes.any.isRequired, // eslint-disable-line
}
class Projects extends Component {
static propTypes = {
classes: PropTypes.any.isRequired, // eslint-disable-line
}
render() {
const { classes } = this.props
return (
<Grid container className={classes.projectPage}
direction="row">
<Grid item xs />
<Grid item>
<Grid container alignItems="center" direction="column">
{/* Title */}
<Grid item>
<Typography className={classes.h5} variant="h5">Latest
Projects</Typography>
</Grid>
<Grid item xs={12} sm={6} component={projectList} />
<Grid item className={classes.nextButton}>
<Button
className={classes.contained}
size="medium"
variant="contained"
onClick={this.handleShowMore}
>
See More
</Button>
</Grid>
</Grid>
</Grid>
<Grid item xs />
</Grid>
)
}
}
export default withStyles(styles)(Projects)
I have this error message appearing
index.js:1452 Warning: Failed prop type: The prop classes is marked as required in projectList, but its value is undefined.
Anyone could help me fix this ?
Not sure where that <Grid/> component comes from but you could pass an inline wrapper for projectLists and return it as a jsx element (you would need a capital first letter though):
<Grid item xs={12} sm={6} component={() => <ProjectList classes={classes} />} />
Don't forget to change the decleration to capital letter:
function ProjectList(props) {
...