Hide/disable arrow buttons of horizontal scroller in react.js - javascript

Hy, I'm trying to disable/hide the arrow buttons of a horizontal scroller on start and end of the scroll.
I tried to use useEffect lifecycle by by setting its dependency document.getElementById('hscroll').scrollLeft, so that i can fire a function on scrollLeft change... but on load it shows an error "Cannot read property 'scrollLeft' of null" which is obviously right.
code is here ... hscroll CodeSandBox
how can I be able to do that?
need your help!
Thank you in advance <3.

You can do that only with useState hook and conditional rendering.
Here's a fully-working solution assuming we know width of the div that wraps your slides:
const HorizontalScroll = () => {
const [slideLeft, setSlideLeft] = useState(0);
const sliderWidth = 1900;
//on arrow click
const moveRight = () => {
const el = document.getElementById(`hscroll`);
setSlideLeft(el.scrollLeft += 200);
};
const moveLeft = () => {
const el = document.getElementById(`hscroll`);
setSlideLeft(el.scrollLeft -= 200);
};
return (
<div className="homepageMargin">
<section style={{ display: "flex", justifyContent: "space-between" }}>
{slideLeft > 0 ? <IconButton onClick={moveLeft}>
<ArrowBackIcon
style={{
paddingTop: ".2rem",
cursor: "pointer"
}}
/>
</IconButton> : <div />}
{slideLeft < sliderWidth ? <IconButton onClick={moveRight}>
<ArrowForwardIcon
style={{
paddingTop: ".2rem",
cursor: "pointer"
}}
/>
</IconButton> : <div />}
</section>
<hr style={{ backgroundColor: "black" }} />
<div class="flex-container" id={`hscroll`}>
{data.map((item) => (
<div style={{ minWidth: "300px" }}>
<img src={item.imgSrc} alt="images" style={{ width: "18rem" }} />
<h6>{item.title}</h6>
</div>
))}
</div>
</div>
);
};
Above example works becouse React component re-render every time you update the state. Also, you can get width of your slider like that:
const sliderWidth = yourRefName.current.style.width;
But it has to be declared explicitly in your CSS.

Related

React is only passing the last object in my array to a component

I have a react component where I map through a list of clients and display each client in a card.
return (
<div className='VolunteerClientsTab'>
{volunteerClients && volunteerClients.map((client) => (
<React.Fragment key={client.id}>
<div className='VolunteerClientsTab__card'>
<Avatar style={{ alignSelf: 'center', marginTop: '.5rem' }}>{client.first_name[0]}{client.last_name[0]}</Avatar>
<h2>{client.first_name} {client.last_name}</h2>
<h4>Details</h4>
<p><AiOutlineMail style={iconStyles} /> {client.email}</p>
<p><AiOutlinePhone style={iconStyles} /> {formatPhoneNumber(client.contact_number)}</p>
<h4 style={{ marginTop: '1rem' }}>Actions</h4>
<p onClick={handleOpenClientNeedsModal} className='hover-underline'><BiDonateHeart style={iconStyles} />View Needs</p>
<p className='hover-underline'><HiOutlineDocumentReport style={iconStyles} />Write Report</p>
<p className='hover-underline'><FiVideo style={iconStyles} />Contact Client</p>
</div>
<ClientNeeds open={openClientNeedsModal} handleClose={handleCloseClientNeedsModal} client={client} />
</React.Fragment>
))}
</div>
)
};
ClientNeeds is a component that renders an MUI modal to display additional client information. I am passing it the client object within the loop but when I open the modal only the client of the last index in the volunteerClients array was passed to all the modal components. Does anyone have any idea why this is happening?
ClientNeeds component
import React from 'react';
import Box from '#mui/material/Box';
import Modal from '#mui/material/Modal';
import PropTypes from 'prop-types';
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
const ClientNeeds = ({ open, handleClose, client }) => {
return (
<div>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<h2>{client.email}</h2>
</Box>
</Modal>
</div>
)
};
ClientNeeds.propTypes = {
open: PropTypes.bool,
handleClose: PropTypes.func,
client: PropTypes.object
};
export default ClientNeeds;
MY SOLUTION
Passing the client onClick to an additional global state object and passing that state object to the modal,
const [selectedClient, setSelectedClient] = useState(null)
also only rendering the clientNeedsModal is there is an object in that state.
<div className='VolunteerClientsTab'>
{volunteerClients && volunteerClients.map((client) => (
<React.Fragment key={client.id}>
<div className='VolunteerClientsTab__card'>
<Avatar style={{ alignSelf: 'center', marginTop: '.5rem' }}>{client.first_name[0]}{client.last_name[0]}</Avatar>
<h2>{client.first_name} {client.last_name}</h2>
<h4>Details</h4>
<p><AiOutlineMail style={iconStyles} /> {client.email}</p>
<p><AiOutlinePhone style={iconStyles} /> {formatPhoneNumber(client.contact_number)}</p>
<h4 style={{ marginTop: '1rem' }}>Actions</h4>
<p onClick={() => handleOpenNeeds(client)} className='hover-underline'><BiDonateHeart style={iconStyles} />View Needs</p>
<p className='hover-underline'><HiOutlineDocumentReport style={iconStyles} />Write Report</p>
<p className='hover-underline'><FiVideo style={iconStyles} />Schedule Meeting</p>
</div>
{selectedClient ? (
<ClientNeeds open={openClientNeedsModal} handleClose={handleCloseClientNeedsModal} client={selectedClient} />
) : null}
</React.Fragment>
))}
</div>
const handleCloseClientNeedsModal = () => {
setSelectedClient(null)
setOpenClientNeedsModal(false);
}
const handleOpenNeeds = (client) => {
setSelectedClient(client)
handleOpenClientNeedsModal()
}
This allows me to pass any individual object within my array to the modal component as originally desired

React-slick - how to change custom arrow colour based on the page number

There are 2 custom arrows which are previous-arrow and next-arrow
There are also total 3 pages with 3 slides per page
What I want to do is whenever the page is the first page/last page, the previous arrow/next arrow will apply filter in svg, which means the previous arrow/next arrow will become black color
<img
…
filter:
"invert(3%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
}}
/>
For example, if it’s the first page, the previous arrow will be filtered while next arrow will NOT be filtered.
Is it possible to do it?
App.js
import "./styles.css";
import React from "react";
import Slider from "react-slick";
import ArrowPrevious from "./arrow-previous.svg";
import ArrowNext from "./arrow-next.svg";
const ArrowButton = ({ imgSrc, imgAlt, onClick }) => {
return (
<button
onClick={onClick}
style={{ backgroundColor: "transparent", border: "none" }}
>
<img
src={imgSrc}
alt={imgAlt}
style={{
width: "50px",
height: "50px",
filter:
"invert(3%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
}}
/>
</button>
);
};
export default function App() {
const settings = {
dots: true,
infinite: false,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3,
prevArrow: <ArrowButton imgSrc={ArrowPrevious} imgAlt="previous-button" />,
nextArrow: <ArrowButton imgSrc={ArrowNext} imgAlt="next-button" />,
beforeChange: (current, next) => {
console.log(next);
}
};
return (
<div>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
</Slider>
</div>
);
}
Codesandbox
https://codesandbox.io/s/focused-dubinsky-9onwe?file=/src/App.js
See codesandbox
https://codesandbox.io/s/inspiring-austin-k9i86?file=/src/App.js:510-527
You just have to look for the onClick !== null
I broke your arrows into 2 separate components though i.e. ArrowButtonNext and ArrowButtonPrevious
const ArrowButtonPrevious = ({ imgSrc, imgAlt, onClick }) => {
return (
<button
onClick={onClick}
style={{ backgroundColor: "transparent", border: "none" }}
>
<img
src={imgSrc}
alt={imgAlt}
style={{
width: "50px",
height: "50px",
filter:
onClick === null
? "invert(93%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
: "none"
}}
/>
</button>
);
};
const ArrowButtonNext = ({ imgSrc, imgAlt, onClick }) => {
return (
<button
onClick={onClick}
style={{ backgroundColor: "transparent", border: "none" }}
>
<img
src={imgSrc}
alt={imgAlt}
style={{
width: "50px",
height: "50px",
filter:
onClick === null
? "invert(93%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
: "none"
}}
/>
</button>
);
};
I have Checked on Code sandbox and inspect the arrow ,you can change only background Color or else you need to import arrow icon from Material UI or Bootstrap

I want to show and hide a form on toggle of a radio button in React js . Im trying how to use react hooks to hide or show a component on onChange even

Now i have used state hook to hide the Form when the page loads. And upon the click or toggle of the radio I'm able to show the Form, But if i toggle the radio again, the form is not hiding.
This is what i have implemented:
const WelcomeTab = () => {
const [toggle, settoggle] = useState(false);
return (
<React.Fragment>
<Tab.Pane
style={{
borderRadius: '7px',
padding: '30px',
}}
attached={false}
>
<Grid>
<Grid.Row>
<Grid.Column floated="left" width={8}>
<Header
style={{
fontSize: '18px',
fontFamily: 'Nunito-Regular',
color: '#4F4F4F',
}}
>
Welcome Screen
</Header>
</Grid.Column>
<Grid.Column floated="right" width={4}>
<Header
as="h4"
style={{
display: 'flex',
justifyContent: 'space-around',
marginLeft: '30px',
}}
>
Customize
<Radio toggle onChange={() => settoggle({ toggle: !toggle })} />
</Header>
</Grid.Column>
</Grid.Row>
</Grid>
{toggle ? (
<Form style={{ paddingTop: '20px' }}>
<Form.Field>
<label style={lableStyle}>Title</label>
<input style={{ marginBottom: '20px' }} />
<label style={lableStyle}>Message</label>
<TextArea />
</Form.Field>
</Form>
) : null}
</Tab.Pane>
</React.Fragment>
);
};
const lableStyle = {
fontFamily: 'Nunito-Regular',
fontWeight: 400,
color: '#4F4F4F',
fontSize: '15px',
display: 'inline-block',
marginBottom: '10px',
};
export default WelcomeTab;
try to add useEffect hook along with change like below,
you no longer need to {} this is old syntax of setState, using hooks we directly make the changes, hope this helps
useEffect(()=>{},[toggle])
replace this wrong syntax code, i can see its not json its boolean value
<Radio toggle onChange={()=>settoggle({toggle: !toggle})}/>
as this is old syntax not work with hooks, try to implment this instead,
<Radio toggle onChange={()=>settoggle(!toggle)}/>

Set Material UI card to max height

I am using Material UI Card as seen here.
I want to set these cards to a maximum height, nicely handling the text and pictures inside. How would I do this?
Here is some code:
<Card className={classes.card} >
<CardHeader
avatar={
<Avatar aria-label={authorAvatar} src={authorImg} className={classes.avatar}/>
}
action={
<Fieldset className={classes.date}>
{postDate}
</Fieldset>
}
title={post.title}
subheader={
<Link to={userUrl}>
{authorName}
</Link>
}
/>
<CardContent>
<div className="content" dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(bodyHtml)}}></div>
</CardContent>
<CardActions className={classes.actions} disableActionSpacing>
<IconButton
className={classnames(classes.unliked, {
[classes.liked]: this.state.liked,
})}
aria-label="Add to favorites"
onClick={this.handleFavourite}
>
I am trying to use sizing and maxHeight, but I cannot get the syntax right.
import maxHeight from '#material-ui/system/sizing';
<CardContent maxHeight = "10">
This gives several errors.
Do I put it here?
const styles = theme => ({
card: {
marginTop: 20,
maxHeight: 300,
},
I got this working in the following way:
import { sizing } from '#material-ui/system/';
const styles = theme => ({
card: {
marginTop: 20,
sizing, maxHeight: 300,
},

React Carousel with text

I am using https://www.npmjs.com/package/react-multi-carousel in one of my react project and I have implemented it and it works fine.
I am now in the need to implement the text (legend) over the carousel exactly like https://codesandbox.io/s/lp602ljjj7 which uses another package but I need that scenario and not that package because my need is different (Using nextjs so multi-carousel supports ssr and hence using it).
My only need is need to know how to implement the legend text over the carousel image using react-multi-carousel.
My code example: https://codesandbox.io/s/react-multi-carousel-playground-bt3v7
Change the structure of the return statement to the following structure.
Then you can store the value of the legend in the image array and pass the value to the p tag
const Simple = ({ deviceType }) => {
return (
<Carousel
ssr
partialVisbile
deviceType={deviceType}
itemClass="image-item"
responsive={responsive}
>
{images.slice(0, 5).map((image, index) => {
return (
<div key={index} style={{ position: "relative" }}>
<img
draggable={false}
alt="text"
style={{ width: "100%", height: "100%" }}
src={image}
/>
<p
style={{
position: "absolute",
left: "50%",
bottom: 0,
color: "white",
transform: " translateX(-50%)"
}}
>
Legend:{index}.
</p>
</div>
);
})}
</Carousel>
);
};
export default Simple;
Live demo
You should change array structure like below.
const images = [
{
image: "https://images.unsplash.com/photo-1549989476-69a92fa57c36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
text: "First image",
}
];
Then inside loop just add text and style it our way!
const Simple = ({ deviceType }) => {
return (
<Carousel
ssr
partialVisbile
deviceType={deviceType}
itemClass="image-item"
responsive={responsive}
>
{images.map(image => {
return (
<div>
<img
draggable={false}
alt="text"
style={{ width: "100%", height: "100%" }}
src={image.image}
/>
{/* Have to style so this should see over the image */}
<span>{image.text}</span>
</div>
);
})}
</Carousel>
);
};

Categories