Iterate through array and display React component one at a time - node.js

I have the following page:
const GalleryPage: NextPage = () => {
const router = useRouter();
const id = router.query.id as string;
return (
<Gallery id={id} imageUrl="someRandomImageUrl.png" />
);
};
And within the Gallery Component, I have
...
return (
<div>
<Form
onSubmit={handleSubmit}
name="judging"
>
<input type="hidden" name="form-name" value="judging" />
<Container text style={{ marginTop: '2em' }} textAlign="center">
<Image src={galleryProps?.imageUrl} size="medium" verticalAlign="middle" />
<Table singleLine>
<Table.Header>
<TableHeader />
</Table.Header>
<Table.Body>
<TableRow
title="Composition"
name="composition"
item={composition}
setItem={setComposition}
/>
<TableRow
title="Creativity - Originality"
name="creativity"
item={creativity}
setItem={setCreativity}
/>
<TableRow
title="Neatness - Finishing details"
name="neatness"
item={neatness}
setItem={setNeatness}
/>
</Table.Body>
</Table>
</Container>
<Container text style={{ marginTop: '1em' }} textAlign="center">
<p>
<Button type="submit">Submit</Button>
</p>
</Container>
</Form>
</div>
);
Where TableRow and TableHeader are custom components.
What I can't seem to make happen
I have an array of image URLs:
const imageUrls = ['firstImageUrl.png', 'secondImageUrl.jpeg', 'thirdImageUrl.png']
And for each item in the imageUrls, I want to display the Gallery component. And only once the form in the Gallery is submitted, do I want the next instance to display with the following image.
ie:
firstcase: <Gallery id={id} imageUrl="firstImageUrl.png" /> once form submitted, second case
secondcase: <Gallery id={id} imageUrl="secondImageUrl.jpeg" /> once form submitted, third case ...

You can create a state called galleryIndex that starts of as 0 and then to gallery you pass a function prop called onSumbit and inside there you increase the state galleryIndex by 1 and then inside the Gallery page you set imageUrl on Gallery component to be the element from the array imageUrls at the index galleryIndex

Related

React: check the pressed key on form submit

I am using React (and Material UI), and I am trying to submit a form. As default by pressing enter when focused on the text field, the form submits. I want it to only happen when I press the Submit button.
The form
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="title"
label="Title"
name="title"
autoComplete="title"
autoFocus
defaultValue={title}
/>
<TextArea setData={setData} data={JSON.parse(description)} />
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Finish
</Button>
<Link href="/">
Back
</Link>
</Box>
The submit function
const handleSubmit = async (e) =>
{
e.preventDefault();
console.log(e)
//
}
This is default behavior since you have your code in a form. It shouldn't matter to you where the users cursor is. This is necessary for screen readers and for basic user experience.
To focus on the next field, the user should be able to tab to the next field.
e.preventDefault is to keep the page from reloading on submit.
I just added onKeyPress to the TextField and checked if the pressed key is equal to Enter
<TextField
margin="normal"
required
fullWidth
id="title"
label="Title"
name="title"
autoComplete="title"
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }} //<----
autoFocus
/>

Is there a way to use a Modal in a React Class Component

I am trying to render a single draft once I click the modal, instead of navigating to the other component... if that makes sense... im getting to display it but then it redirects me because of the Link.. but if i dont add the Link then I loose my draftId on url
This is part of my code
class Drafts extends React.Component {
componentDidMount() {
this.props.fetchAllDrafts()
}
render() {
const drafts = this.props.drafts
return (
<React.Fragment>
<Table aria-label="a dense table" className="myaccount-table">
<TableHead>
<TableRow>
<TableCell align="center">
<div className="date-content">Date</div>
</TableCell>
<TableCell align="center">Content</TableCell>
<TableCell> </TableCell>
<TableCell> </TableCell>
</TableRow>
</TableHead>
<TableBody>
{drafts.map((draft) => (
<TableRow key={draft.id}>
<TableCell>
<div className="datecontent">{draft.createdAt}</div>
</TableCell>
<TableCell>
<div className="content">{draft.content} </div>
</TableCell>
<TableCell>
<Link to={`/drafts/${draft.id}`}>
<Popup
trigger={<button className="button"> Read </button>}
modal
nested
>
<SingleDraft />
{/* <Button color="primary">
Read
</Button> */}
</Popup>
</Link>
the is comming from another class component
class SingleDraft extends React.Component {
constructor() {
super()
}
componentDidMount() {
this.props.fetchDraft(this.props.match.params.draftId)
}
render() {
return (
<div>
<p>{this.props.singleDraft.content} </p>
<Link to={`/texteditor/${this.props.singleDraft.id}`}>
<button>Update</button>
</Link>
</div>
)
}
Why don't you pass the draftId as a prop?
<Popup
trigger={<button className="button"> Read </button>}
modal
nested
>
<SingleDraft draftId={draft.id} />
{/* <Button color="primary">Read</Button> */}
</Popup>
And in your component.
componentDidMount() {
this.props.fetchDraft(this.props.draftId)
}

How to make Material-UI GridListTitleBar and Image a Link in ReactJS

I am using Material UI GridList to display a list of Events in React. Everything is working fine except that I am not able to make Title or Image a Link. Does anyone know how to make Title and Image a Link?
Here is my Component.
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
key={Math.floor(Math.random() * new Date().getTime())}
>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.description}</span>}
actionIcon={<IconButton title={tile.title} />}
/>
</GridListTile>
);
})}
</GridList>
</div>
);
Update
This is an update to the answer that was given below. The first image is now smaller than the rest of the images after update the code with the solution given below.
Here is the new code that I am trying:
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
key={Math.floor(Math.random() * new Date().getTime())}
>
<a href={"events/" + tile._id + "/eventcomments"}>
<img
src={tile.eventImage}
alt={tile.title}
className="MuiGridListTile-imgFullHeight"
/>
<GridListTileBar title={tile.title} />
</a>
</GridListTile>
);
})}
</GridList>
</div>
Try wrapping the image with an anchor tag like this:
// ...
<GridListTile key={Math.floor(Math.random() * new Date().getTime())}>
<a href="https://www.google.com/">
<img src={tile.eventImage} alt={tile.title} className="MuiGridListTile-imgFullHeight" />
</a>
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.description}</span>}
actionIcon={<IconButton title={tile.title} />}
/>
</GridListTile>
// ...
It is important, after wrapping the image inside an anchor tag to add the class MuiGridListTile-imgFullHeight to the image to keep the same styling of the grid. Normally this class is added automatically, but if you wrap it inside an anchor tag it isn't. So you need to add it manually.
Update
The image shows expected behavior, because your first image is not wide enough to cover the whole tile and you only added the class to scale the img to full height. There is also a class to scale to full width: MuiGridListTile-imgFullWidth, but you can't use both of these classes together for your use case as the styles conflict (see the style definition here: https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/GridListTile/GridListTile.js).
You can try to set the width to 100% in the image style prop:
<img
// ...
style={{ width: "100%" }}
className="MuiGridListTile-imgFullHeight"
/>
I eventually managed to get it to work without breaking or stretching my images, and here is what I did.
<div className={classes.root}>
<GridListTile key="Subheader" style={{ height: "auto" }}>
<ListSubheader component="div">This is List of Events</ListSubheader>
</GridListTile>
<GridList
cellHeight={330}
cols={matches ? 1 : 3}
className={classes.gridList}
spacing={12}
>
{tileData.length > 0 &&
tileData.map((tile, index) => {
return (
<GridListTile
component={Link}
to={"/events/" + tile._id + "/eventcomments"}
key={Math.floor(Math.random() * new Date().getTime())}
>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar title={tile.title} />
</GridListTile>
);
})}
</GridList>
</div>
const Gallery = () => {
const classes = useStyles();
return (
<Fragment>
<div style={{background: "black"}}>
<Toolbar/>
<Grid container spacing={0}>
<Grid item xs={12}>
<Paper className={classes.paper}>GALERIA</Paper>
<div className={classes.root}>
<GridList cellHeight={280} className={classes.gridList} cols={1}>
{tileData.map((tile) => (
<GridListTile style={{ width: "100%" }} key={tile.img} cols={tile.cols || 1}>
<img src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>
</div>
</Grid>
</Grid>
</div>
</Fragment>
)
}
export default Gallery;
You can change the type of underlying component rendered by the GridListTime Material-UI component. Just add the component="a" to have it render as an anchor tag. Then you may specify an href prop to pass in your route. See below:
<GridList cellHeight={160} className={classes.gridList} cols={3}>
{tileData.map((tile) => (
<GridListTile key={tile.img} cols={tile.cols || 1} component="a" href="/">
<img src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>

How to create onSubmit with Material-UI

So I'm fairly new to node.js / react / material-ui. I've been following a guide to try setting up a website and have been getting on pretty well. I decided to include material-ui for snazzy components (not part of the guide) and then got stuck because I can't seem to fire custom functions whilst using a themed ui.
With the below code, I can create everything fine if I ditch the 'classes' props. I can add my function and everything works. But I obviously lose all my styling if I do this.
const styles = theme => ({
// Styling - omitted
});
const Login = (props) => {
const {classes} = props;
return(
<div>
<Paper className={classes.root}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id="email"
label="Email"
className={classes.textField}
InputProps={{
className: classes.input
}}
type="email"
name="email"
autoComplete="email"
margin="normal"
variant="outlined"
required
autoFocus
/>
<TextField
id="outlined"
label="Password"
className={classes.textField}
InputProps={{
className: classes.input
}}
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
required
/>
<Typography className={classes.divider} />
<Button
type="submit"
variant="contained"
color="inherit"
className={classes.button}
>
Login
</Button>
</form>
</Paper>
</div>
);
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Login);
I'm trying to combine the styling as well as being able to fire a custom function to submit the form data. Does anyone have any thoughts?
The class property/ styles shouldn't have any effect on form submission custom function. If you think that ditching the 'class props' you can get a custom function to work - post your code so we can help you further. [Your code is missing submit function]
Here is one way to add custom submit function
const Login = (props) => {
const {classes} = props;
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
function handleSubmit(event) {
event.preventDefault();
console.log( 'Email:', email, 'Password: ', password);
// You should see email and password in console.
// ..code to submit form to backend here...
}
return( <div >
<Paper className={classes.root}>
<form className={classes.container} onSubmit={handleSubmit} >
<TextField
....
value={email}
onInput={ e=>setEmail(e.target.value)}
.....
/>
<TextField
....
value={password}
onInput={ e=>setPassword(e.target.value)}
....
/>
<Typography className={classes.divider} />
<Button
type="submit"
....
className={classes.button}
>
Login
</Button>
</form>
</Paper>
</div>
);

how to get multiple checkbox value using AlloyUI

I want to get multiple checkbox values from the listed select checkboxes on submit button. I have tried with node-event-delegate but it's not working:
AUI().use('node', 'event', 'node-event-delegate', function (A) {
var allcheckboxes = A.one('.plans').all(':checked');
console.info(allcheckboxes.size()); // It will give number selected checkboxes
A.all('.compare-products').each(function (node) {
console.info(node.currentTarget);
console.info(node, A.one(node(':checkbox:checked')));
if (A.one(node.currentTarget).all(':checked')) {}
});
A.all('.compare-products input[type="checkbox"]').filter(':not(:checked)').setAttribute("disabled", "disabled"); // it will disable the unchecked checkboxes
A.all('.compare-products input[type="checkbox"]').filter(':not(:checked)').removeAttribute("disabled", "disabled"); // it will remove disable attribute from unchecked checkboxes
});
HTML Code
<div>
<div>
<input type="checkbox" class="product" name="product1" value="product1" /> product1<br />
<input type="checkbox" class="product" name="product2" value="product2" /> product2<br />
<input type="checkbox" class="product" name="product3" value="product3" /> product3<br />
<input type="checkbox" class="product" name="product4" value="product4" /> product4<br />
<input type="checkbox" class="product" name="product5" value="product5" /> product5<br />
</div>
<button>Compare Products</button></div>
AUI Script Code
AUI().use("node", function(A){
A.one("button").on("click", function(){
var values = [];
A.all("input[type=checkbox]").each(function(){
if(this.get("checked")){
values.push(this.get("value"));
}
});
console.log(values);
}); });

Resources