React prevent body from scrolling if popup is open - reactjs

React prevent body from scrolling if popup is open.
How can i disable the background body from scrolling when the pop up div is open.
function FilterButton() {
let [isOpen, setIsOpen] = useState(false);
return (
<div className='filter-button'>
<div className="name-filter" onClick={() => setIsOpen(!isOpen)}>
<p>Filter</p>
<i class="fas fa-filter"></i>
</div>
{
isOpen ? <div className="background-blur">
<div className="filter-popup">
<p className='filter-by-name'>Filter By Type</p>
<hr />
<div className="filter-types">
<div className="filter">
<input type="checkbox" />
<p></p>
</div>
</div>
<div className="apply-cancel">
<button className="apply">Apply</button>
<button className="cancel" onClick={() => setIsOpen(!isOpen)}>Cancel</button>
</div>
</div>
</div>
: null
}
</div>
)
}

You can use the body-scroll-lock library to help you with that.
Here is how it could work on your component. I haven't tested it tho.
import { useState, useRef, useEffect } from 'react';
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks
} from 'body-scroll-lock';
function FilterButton() {
const [isOpen, setIsOpen] = useState(false);
const popupRef = useRef(null)
useEffect(() => {
if (isOpen) {
popupRef.current && disableBodyScroll(popupRef.current)
} else {
popupRef.current && enableBodyScroll(popupRef.current)
}
}, [isOpen])
return (
<div className="filter-button">
<div className="name-filter" onClick={() => setIsOpen(!isOpen)}>
<p>Filter</p>
<i class="fas fa-filter"></i>
</div>
{isOpen ? (
<div className="background-blur">
<div className="filter-popup" ref={popupRef}>
<p className="filter-by-name">Filter By Type</p>
<hr />
<div className="filter-types">
<div className="filter">
<input type="checkbox" />
<p></p>
</div>
</div>
<div className="apply-cancel">
<button className="apply">Apply</button>
<button className="cancel" onClick={() => setIsOpen(!isOpen)}>
Cancel
</button>
</div>
</div>
</div>
) : null}
</div>
);
}

Related

nextjs and bootstrap5 modal

Hello I would like to use bootstrap 5 without react-bootstrap and reactstrap when I create my modal I end up with this error:
TypeError: undefined is not an object (evaluating 'this._element.classList')
Do you have any idea because all the examples I am viewing are still with reactstrap or react-bootstrap, do you have any idea how to do this, thanks for your help.
import Document, { Html, Head, Main, NextScript } from "next/document";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
<div id="modal-root"></div>
</body>
</Html>
);
}
}
export default MyDocument;
My modal
import { useState, useEffect } from "react";
import ReactDom from "react-dom";
const Modal = ({ show, onClose, children, title, targetModal }) => {
const [isBrowser, setIsBrowser] = useState(false);
useEffect(() => setIsBrowser(true));
const handleCloseModal = (e) => {
e.preventDefault();
let myModalEl = document.getElementById(targetModal);
console.log(myModalEl);
onClose();
};
const modalContent = show ? (
<div
className="modal fade py-3"
tabIndex="-1"
role="dialog"
id={targetModal}
>
<div className="modal-dialog" role="document">
<div className="modal-content border-0 rounded-6 shadow-blue-sm">
<div className="modal-header p-4 pb-4 border-bottom-0">
<h4 className="fw-bold mb-0 hstack text-secondary">
{title && (
<span>
<i className="ri-user-search-line me-2"></i> {title}
</span>
)}
</h4>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
onClick={handleCloseModal}
aria-label="Close"
></button>
</div>
<div className="modal-body p-4 pt-0">{children}</div>
</div>
</div>
</div>
) : null;
if (isBrowser) {
return ReactDom.createPortal(
modalContent,
document.getElementById("modal-root")
);
} else {
return null;
}
};
export default Modal;
My Page
import { useState } from "react";
import Layouts from "#/components/Layouts";
import Modal from "#/components/Modal";
const EditEventsPage = () => {
const [showModal, setShowModal] = useState(false);
return (
<Layouts title="Edit event.">
<button
type="submit"
className="btn btn-secondary mt-4 hstack"
data-bs-toggle="modal"
data-bs-target="#uploadImage"
onClick={() => setShowModal(true)}
>
<i className="ri-image-line "></i> Ajouter image{" "}
</button>
<Modal
show={showModal}
onClose={() => setShowModal(false)}
targetModal="uploadImage"
></Modal>
</Layouts>
);
};
export default EditEventsPage;
Thansk for your helps.
I have not been able to achieve this using your method.
However, this works for me, and you could expand on the example.
in your _app.js file add this line of code, you should wrap it in the useEffect function as so
useEffect(() => {
typeof document !== undefined
? require("bootstrap/dist/js/bootstrap")
: null;
},[]);
This will make bootstrap available across your project. So where ever you want to trigger your modal.
just do this instead
<button type="button" data-bs-toggle="modal" data-bs-target="#myModal">Launch modal</button>
Your Bootstrap modal
<div
className="modal modal-alert bg-secondary py-5"
tabIndex="-1"
role="dialog"
id="myModal"
>
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content rounded-4 shadow">
<div className="modal-body p-4 text-center">
<h5 className="mb-0">Enable this setting?</h5>
<p className="mb-0">
You can always change your mind in your account settings.
</p>
</div>
<div className="modal-footer flex-nowrap p-0">
<button
type="button"
className="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-right"
>
<strong>Yes, enable</strong>
</button>
<button
type="button"
className="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0"
data-bs-dismiss="modal"
>
No thanks
</button>
</div>
</div>
</div>
</div>
Hope this helps.

Display different values in a popup in React

I am trying to have a popup for editing profile information in react, and I want there to be a button by each value that will allow a user to edit that specific value. The popup works, except it will only display the last value that I have put in. I think it is because I need to reset the state each time the button is clicked, but I am still fairly new to react so I am not sure how to do it.
I will add my code, however it is pulling some information from a local database, so let me know if you need me to remove things.
Here is the component for the popup
import React from 'react'
const Popup = props => {
console.log(props)
return(
<div className='popup-box'>
<div className='box'>
<span className='close-icon' onClick={props.handleClose}>x</span>
{props.content}
</div>
</div>
)
}
export default Popup
And here is the component page where the popup appears
import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { getUser } from '../apiClient'
import Nav from './Nav'
import EditPopup from './EditPopup'
export default function UserProfile (props) {
const [isOpen, setIsOpen] = useState(false)
const togglePopup = () => {
setIsOpen(!isOpen)
}
const [user, setUser] = useState({
user: []
})
useEffect(() => {
getUser(props.match.params.id)
.then((res) => {
setUser(res)
})
.catch((error) => {
console.log('error', error.message)
})
}, [])
return (
<div className='globalBackground'>
<Nav />
<div className='UserInfoForm'>
<div className='profile-heading' >
<h1>General User Information</h1>
</div>
<div className='profile-Pic' >
<div className='profile-pic-heading'>
<h2>Profile Picture</h2>
</div>
<div className='profile-pic-display'>
<img src={user.profilePic} style={{ width: '150px', height: '150px' }}
alt=''
/>
</div>
</div>
<div className='UsernameEdit'>
<h2>Username</h2>
<p>{user.username}</p>
<input type='button' value='Edit' onClick={togglePopup} />
{isOpen && <EditPopup
content={<>
<b>Edit Your Username</b>
<div className='userNameEditInput'>
<input className='usernameEdit' placeholder={user.username} />
</div>
<button>Save Changes</button>
</>}
handleClose={togglePopup}
/>}
<div />
<div className='EmailEdit'>
<h2>Email</h2>
<p>{user.email}</p>
<input type='button' value='Edit' onClick={togglePopup} />
{isOpen && <EditPopup
content={<>
<b>Edit Your Email</b>
<div className='emailEditInput'>
<input className='emailEdit' placeholder={user.email} />
</div>
<button>Save Changes</button>
</>}
handleClose={togglePopup}
/>}
</div>
<div className='CountryEdit'>
<h2>Country</h2>
<p>{user.country}</p>
<input type='button' value='Edit' onClick={togglePopup} />
{isOpen && <EditPopup
content={<>
<b>Edit Your Country</b>
<div className='countryEditInput'>
<input className='countryEdit' placeholder={user.country} />
</div>
<button>Save Changes</button>
</>}
handleClose={togglePopup}
/>}
</div>
<div className='RegionEdit'>
<h2>Region</h2>
<p>{user.region}</p>
<input type='button' value='Edit' onClick={togglePopup} />
{isOpen && <EditPopup
content={<>
<b>Edit Your Region</b>
<div className='regionEditInput'>
<input className='regionEdit' placeholder={user.email} />
</div>
<button>Save Changes</button>
</>}
handleClose={togglePopup}
/>}
</div>
<div className='HandicapEdit'>
<h2>Handicap</h2>
<p>{user.handicap}</p>
<input type='button' value='Edit' onClick={togglePopup} />
{isOpen && <EditPopup
content={<>
<b>Edit Your Handicap</b>
<div className='handicapEditInput'>
<input className='handicapEdit' placeholder={user.handicap} />
</div>
<button>Save Changes</button>
</>}
handleClose={togglePopup}
/>}
</div>
</div>
</div>
</div>
)
}
Let me know if there's any other code needed, any help would be greatly appreciated :--)
You can remove the state from the UserProfile and move it inside the Popup Component.
import React from 'react';
const Popup = (props) => {
const [toggle, setToggle] = useState(false);
const togglePopup = () => setToggle((prevToggle) => !prevToggle);
return (
<>
<input type="button" value="Edit" onClick={togglePopup} />
{toggle && (
<div className="popup-box">
<div className="box">
<span className="close-icon" onClick={togglePopup }>
x
</span>
{props.content}
</div>
</div>
)}
</>
);
};
export default Popup;
You can then use EditPopup as below in the UserProfile.
{
<div className='UsernameEdit'>
<h2>Username</h2>
<p>{user.username}</p>
<EditPopup
content={<>
<b>Edit Your Username</b>
<div className='userNameEditInput'>
<input className='usernameEdit' placeholder={user.username} />
</div>
<button>Save Changes</button>
</>
}
/>
<div />
}

First key press is not working by using react hook form controlled component

I used react hook form for validations purpose. but our code is implemented on controlled components. I went through few examples in google that use default value instead of value.
If I replace the value with the default value after submitting a form. The values in the form are not clearing can anyone suggest to me how to overcome this.
import React, { useState, useEffect } from 'react';
import { getIdToken } from '../Utils/Common';
import { useForm } from 'react-hook-form';
export default function Roles() {
const [roleName, setroleName] = useState('');
const { register, handleSubmit, errors } = useForm();
const handleRoleName = (event) => {
setroleName(event.target.value);
};
const handleAddRole = () => {
/* api call here after succes i have clear role name*/
setroleName('');
};
}
return (
<div className='g-pa-20'>
<h1 className='g-font-weight-300 g-font-size-28 g-color-black g-mb-28'>
{editaddLabel}
</h1>
<form noValidate onSubmit={handleSubmit(handleAddRole)}>
<div className='row'>
<div className='col-md-4 col-xs-12 col-sm-12'>
<div className='g-brd-around g-brd-gray-light-v7 g-rounded-4 g-pa-15 g-pa-20--md g-mb-30'>
<div className='mb-4'>
<div className='form-group g-mb-30'>
<label className='g-mb-10' for='inputGroup-1_1'>
Role Name
</label>
<div
className={
errors && roleName === ''
? 'g-err-brd-primary--focus'
: 'g-pos-rel'
}
>
<span className='g-pos-abs g-top-0 g-right-0 d-block g-width-40 h-100 opacity-0 g-opacity-1--success'>
<i
className='hs-admin-check g-absolute-centered g-font-size-default g-color-secondary'
on
></i>
</span>
<input
id='inputGroup-1_1'
className='form-control form-control-md g-brd-gray-light-v7 g-brd-gray-light-v3--focus g-rounded-4 g-px-14 g-py-10'
type='text'
placeholder=''
onChange={handleRoleName}
value={roleName}
name='role'
ref={register({
required: true,
})}
/>
</div>
{errors.role && errors.role.type === 'required' && (
<p className='plans-single-error'> Role name is required.</p>
)}
</div>
</div>
<div className='from-group'>
<div className='form-row pull-right'>
<div className='form-group col-xs-6'>
<button
className='btn btn-md btn-xl--md u-btn-primary g-font-size-12 g-font-size-default--md g-mr-10 g-mb-10'
disabled={loading}
>
{loading && (
<i className='fas fa-spinner fa-spin spinner'></i>
)}
Save
</button>
</div>
<div className='form-group col-xs-6'>
<button
className='btn btn-md btn-xl--md u-btn-outline-gray-dark-v6 g-font-size-12 g-font-size-default--md g-mb-10'
onClick={cancelClick}
>
Cancel
</button>
</div>
</div>
</div>
<div className='from-group'>
<label></label>
</div>
</div>
</div>
</div>
</form>
</div>
);

When conditionally exporting functions components in react I cannot access my useState variables. Any Solutions?

Here is my file with two components that are supposed to conditionally render. The problem is right before I export I cannot use my variables from isLoggedIn (u, useradmin, p, passadmin).
import React, { Fragment, useState } from "react";
import "./SignIn.css";
import { Link } from "react-router-dom";
const isLoggedIn = (user, pass) => {
let u = user.toString();
let p = pass.toString();
let useradmin = "bilal";
let passadmin = "123";
console.log(u)
console.log(p)
if (u === useradmin && p === passadmin) {
console.log("success")
return (
<Fragment>
<button type="button" className="btn btn-warning" data-toggle="modal">Head to Admin</button>
<div className="modal fade">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title text-dark">Successfully Signed In!</h4>
<button type="button" className="close" data-dismiss="modal" ></button>
</div>
<div className="modal-body">
<input type="text" className="form-control" />
</div>
<div className="modal-footer">
<Link to="/adminqueue">
<button type="button" className="btn btn-danger" data-dismiss="modal">Enter Admin Queue</button>
</Link>
</div>
</div>
</div>
</div>
</Fragment>
)
}
}
const SignIn = () => {
const [user, setUser] = useState('');
const [pass, setPass] = useState('');
return (
<Fragment>
<div className="login-box">
<h1>Admin Log In</h1>
<form>
<div className="textbox">
<i className="fas fa-user" />
<input onChange={event => setUser(event.target.value)} type="text" placeholder="Username" />
</div>
<div className="textbox">
<i className="fas fa-lock" />
<input onChange={event => setPass(event.target.value)} type="password" placeholder="Password" />
</div>
<button className="button" type="button" value="Sign in" onClick={() => isLoggedIn(user, pass)} >SignIn</button>
</form>
</div>
</Fragment>
)
}
const exp = u === useradmin && p === passadmin ? isLoggedIn : SignIn;
export default exp;
This is just text because Stack Overflow Says I have too much code (IGNORE).

React Hover to conditional render component

this is my code so far
class PortfolioList extends Component{
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div className="thumbnail-inner" >
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</React.Fragment>
)
}
}
I want to conditionally render the div "content" and the child elements of content div when mouse is hovering over "thumbnail-inner" div. But hide content when mouse is not hovering over thumbnail-inner div.
How can i achieve this?
I didn't test this, but the idea is to add a variable in the state of the component which holds the current hovered item.
When a mouseEnter event enters to your thumbnail-inner, you update that variable with the current component index. And you set it to -1 when a mouseLeave events happens in your thumbnail-inner.
Then you simply render the content conditionally by checking if the this.state.selectedIndex === index.
class PortfolioList extends Component {
state = {
selectedItem: -1,
}
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div
className="thumbnail-inner"
onMouseEnter={ () => { this.setState({selectedItem: index}) } }
onMouseLeave={ () => { this.setState({selectedItem: -1}) } }>
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
{
this.state.selectedItem === index &&
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
}
</div>
</div>
))}
</React.Fragment>
)
}
First, you need to add state for condition of hover (ex: "onHover"), the state is for conditional rendering the <div className="content">.
Second you need create function for hover and leaveHover(onMouseEnter & onMouseLeave) we call it handleMouseEnter for onMouseEnter, and we call it handleMouseLeave for onMouseLeave.
class PortfolioList extends Component {
state = {
onHover: false,
}
handleMouseEnter() {
this.setState({onHover: true})
}
handleMouseLeave() {
this.setState({onHover: false})
}
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div
className="thumbnail-inner"
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}>
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
{
this.state.onHover &&
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
}
</div>
</div>
))}
</React.Fragment>
)
}

Resources