Modal visible in HTML but on visible on app - javascript

Struggling to get my modal rendering when I click a button to show it. Here is the flow of this functionality
We start off by triggering toggle when the start coding button is clicked:
Start Coding
</button>
<StartModal
isShowing={isShowing}
hide={toggle}
/>
toggle is passed down from useModal()
const { isShowing, toggle } = useModal();
userModal changes the state of isShowing to true/false
import { useState } from 'react';
const useModal = () => {
const[isShowing, setIsShowing] = useState(false);
function toggle() {
console.log('toggle is being triggered')
setIsShowing(!isShowing);
}
return {
isShowing,
toggle,
};
};
export default useModal;
At this point toggle is being triggered is console logged
StartModal then should become visible:
import React from "react";
import "../../assets/scss/modal.scss"
import ReactDOM from 'react-dom';
const StartModal = ({ isShowing, hide }) => isShowing ? ReactDOM.createPortal(
<>
<div className="md-modal md-effect-12">
<div className="md-content">
<h3>Ready to start programming?</h3>
<div>
<p>The session will be split into 5 phases:</p>
<ul>
<li>Introductions</li>
<li>Pseudo-Code</li>
<li>Time to Code</li>
<li>Solution</li>
<li>Rating</li>
</ul>
<button
className="md-close"
onClick={hide}
>Close</button>
</div>
</div>
</div>
<div className="md-overlay"></div>
</>, document.body
) : null;
export default StartModal;
When I click the start coding button, my modal appears in my HTML. When I check the Elements tab on my browser, I see the modal showing up but cannot see it on my screen. I don't think it is a css problem because I have a z-index: 2000 property on the parent div. It seems as though the div appears outside of my react components?

I think the best approach is to use it with a new div.
For example:
<body>
<div id="root"></div>
<div id="modal"></div>
</body>
so you can look it here: https://codesandbox.io/s/affectionate-banzai-xypu3i

Related

Open Modal in App.js from a button in another component

So I have three components in my app.
App.js
HeroSection.js
Modal.js
The button I have for opening the Modal is in HeroSection. But I need the Modal to render from App.js due to how the styling is structured. When it is opened from HeroSection, it opens in a container that doesn't allow me to position the Modal in the center of the screen (It's in a CSS grid set up). I hope I'm making sense.
My code:
const App = ({ signOut }) => {
return (
<div>
<button onClick={clickOpenAccountModal} className='add-account'>Add Account</button>
{openAddAccountModal && <Modal closeModal={setOpenAddAccountModal} />}
<div className="App">
<div className='nav-pane'>
<SideBar signOut={signOut} />
</div>
<div className='content-pane'>
<MainContent />
</div>
</div>
</div>
);
}
const HeroSection = () => {
// Add Acount Button
const [openAddAccountModal, setOpenAddAccountModal] = useState(false);
const clickOpenAccountModal = () => {
setOpenAddAccountModal(true);
}
// Add Transaction Button
const [openAddTransactionModal, setOpenAddTransactionModal] = useState(false);
const clickOpenTransactionModal = () => {
setOpenAddTransactionModal(true);
}
return (
<div className='hero-section'>
<h1 className='page-title'>Users's Dashboard</h1>
<div className='hero-buttons'>
<button onClick={clickOpenAccountModal} className='add-account'>Add Account</button>
{openAddAccountModal && <Modal closeModal={setOpenAddAccountModal} />}
<button onClick={clickOpenTransactionModal} className='add-transaction'>Add Transaction</button>
{openAddTransactionModal && <Modal closeModal={setOpenAddTransactionModal} />}
</div>
</div>
);
}
const Modal = ({ closeModal }) => {
return (
<div className='modal-background'>
<div className='modal-container'>
<div className='title-container'>
<h2>Add Account</h2>
<button className='exit-button' onClick={() => closeModal(false)}>X</button>
</div>
</div>
</div>
);
}
Main App
How the modal opens in HeroSection
How I need it to open from the button in HeroSection
I tried copying the logic for opening and closing the modal directly to App.js, but to get that to work, I had to put the button used to open the Modal in App.js as well. I need the button to stay in HeroSection and render from App.js
How can I accomplish this?
It is more valid to put the button in the HeroSection component and let the modal be opened in the App.js component. So to start it's the correct approach.
For the implementation there are 2 options:
1-
If the application won't grow to much more components, you can still have the open modal button in the HeroSection component. And that HeroSection component can take a callback function as a prop (for ex openModal) which it can calls when the button is clicked. That way when the function runs you implement the logic for opening/closing the modal in the App.js.
Check solution 1 in react codesandbox
2-
If the application can grow to many components, solution 1 will create unmaintainable code in the long run.
To address this, you can start using a general state management library like redux
When you do that, you can open/close a modal from any component you want without passing any modal specific prop to that component
In general applications, the more correct approach is solution 2. But it can be unnecessary complexity if the application only contains 3 component

How to catch different events from dom elements (div/img/input) and how to interact(get/set attributes,styles,classes) with them with react js?

for example we have this button
and this div
<button onClick={test_func}>
</button>
<div class="js_test">
</div>
in jquery we do so !
$(document).on('click', '.js_test', fu
//code
});
$(document).on('EVENT_TYPE', 'ELEMENT_DOM', function(evt) {});
$('ELEMENT_DOM').css();
$('ELEMENT_DOM').attr();
$('ELEMENT_DOM').addClass();
in js you can catch all events by class or id
.js_test
so how is it like in React.js
test_func() {
//inside here i need to do something with div .js_test
// to set text, add new class, set new css style like color: 'red' for example
}
You can receive the event in the function, and use e.target (.nextElementSibling to target the div close to the button) Or you can use the useRef hook, and use ref.current
import { useState } from "react";
import { useRef } from "react"
function Teste(){
const ref = useRef();
const [darkMode, setDarkMode] = useState(false);
function AlterWithEDotTarget(e){
e.target.nextElementSibling.innerHTML = "WAS ALTERED!"
}
function AlterWithUseRef(){
ref.current.innerHTML = "WAS ALTERED!";
}
function ToggleDarkMode() {
setDarkMode(!darkMode)
}
return (<>
<button onClick={AlterWithEDotTarget}>Alter With e.target</button>
<div>Will be altered with e.target {darkMode ? "DarkMode ON" : ""}</div>
<br/>
<br/>
<button onClick={AlterWithUseRef}>Alter With useRef</button>
<div ref={ref}>Will be altered with useRef {darkMode ? "DarkMode ON" : ""}</div>
<br/>
<br/>
<button onClick={ToggleDarkMode}>Toggle Dark Mode</button>
</>)
}
export default Teste
EDIT
In react things are different than jQuery, i added an example targeting multiple elements, you do it using state, and binding the state to the elements, and when the state changes, the elements change as well

Animate on scroll using react.js

I am using some css animations from animate.css and I'm using react.js which works fine at the top of my page however, I also have some animations near the middle of the page. When my page loads everything animates at once which means once I scroll down the animations in the middle of the page have already completed. I am looking for away to delay the animations until that area of the screen is visible. I have found some questions/answers on here but they date back quite a few years and appear to be outdated.
As seen in the code below the animate__animated animate__bounce animate__zoomInDown classes are derived from animate.css but play immediately when the page is loaded and not when visible onscreen:
import React from "react";
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faHourglassStart} from '#fortawesome/free-solid-svg-icons'
function MiddleContainer() {
return (
<div>
<div id = "middle-container" class="middle-container">
<h1>What can I offer you?</h1>
<div className = "fast animate__animated animate__bounce animate__zoomInDown">
<FontAwesomeIcon className="social-icon" icon={faHourglassStart} size = '4x' color = "black"/>
<h4>Fast and Reliable Service</h4>
<p>Your product will be delivered to you with precision, care and in a timely manner.</p>
<p>Add more info here when you are done with the css. </p>
</div>
</div>
</div>
)
}
export default MiddleContainer;
So I was able to solve this myself using a different library as I couldn't find any documentation from animate.css on how to animate on scroll
The new library with documentation that worked is AOS from https://michalsnik.github.io/aos/
I had to use useEffect from react.js in order for it to work.
Here is my code with animate on scroll working:
import React, { useEffect } from "react";
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faHourglassStart} from '#fortawesome/free-solid-svg-icons'
import AOS from "aos";
import "aos/dist/aos.css";
function MiddleContainer() {
useEffect(() => {
AOS.init({
// duration : 5000
});
}, []);
return (
<div>
<div id = "middle-container" class="middle-container">
<h1>What can I offer you?</h1>
<div className = "fast" data-aos="zoom-in">
<FontAwesomeIcon className="social-icon" icon={faHourglassStart} size = '4x'
color = "black"/>
<h4>Fast and Reliable Service</h4>
<p>Your product will be delivered to you with precision, care and in a
timely manner.</p>
<p>Add more info here when you are done with the css. </p>
</div>
</div>
</div>
)
}
export default MiddleContainer;

React js - Show or hide a div

I am trying to show or hide a div in Reactjs using the state value in the CSS style option - display and I am using functions with hooks. I have a button and below the button a div. When i click the button i either want to hide or show the contents in the div based on whether it is currently shown or hidden.
This is the basic test code I have
import React, { useState } from "react";
function hide() {
return (
<div>
<Mycomp />
</div>
);
}
function Mycomp() {
const [dp, setDp] = useState("none");
return (
<form>
<button
onClick={() => {
setDp("block");
}}
>
Test
</button>
<div style={{ display: dp }}>Test</div>
</form>
);
}
export default hide;
I then use this hide component in my App.js file. When I click the button the new state is assigned but then the page re-renders and the initial state is loaded again almost immediately. How can I go by ensuring the new state is kept? Eventually I will create a function where if the div display or not based on the previous state.
The issue is that the button is inside a <form>. So any click on that button will submit the form and refresh the page.
Can I make a <button> not submit a form?
You need to add a type="button" to your <button>
import React, { useState } from "react";
function Hide() {
return (
<div>
<Mycomp />
</div>
);
}
function Mycomp() {
const [dp, setDp] = useState(false);
return (
<form>
<button
type="button"
onClick={() => setDp(!dp)}
>
Test
</button>
{dp && <div>Test</div>}
</form>
);
}
export default Hide;
Your code should be something like this, instead of using block and none as style we can use conditional JSX (which is more ideal approach) -:
function Mycomp(){
const[dp, toggleDp] = useState(false);
return(
<form>
<button onClick={()=>{toggleDp(!dp)}}>Test</button>
{dp && <div>Test</div>}
</form>
)
}
export default hide
A better implementation would be to have your state variable TRUE/FALSE value and based on it display the element using a conditional rendering, note e.preventDefault in the button handler to stop the refresh/redirect, here is a working snippet, also a codesandbox:
const { useState, useEffect } = React;
function App() {
return (
<div>
<Mycomp />
</div>
);
}
function Mycomp() {
const [dp, setDp] = useState(true);
return (
<form>
<button
onClick={(e) => {
e.preventDefault();
setDp(!dp);
}}
>
Test
</button>
{dp && <div>Test</div>}
</form>
);
}
ReactDOM.render(<App />, document.getElementById("react-root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

Using ReactModal button with Href, not working. Unsure why

I am fairly new to react and have redone my personal site in react. The issue I am running into is my button that links (with href) to my JSfiddle for each portfolio demo is not working. I am not sure if I did not bind correctly or what exactly the issue is other than when the modal is open, the Demo button does not work. Close modal button works fine. Please see code below.
import React from 'react';
import ReactModal from 'react-modal';
class Project extends React.Component {
constructor () {
super();
this.state = {
showModal: false
};
this.handleOpenModal = this.handleOpenModal.bind(this);
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleOpenModal() {
this.setState({ showModal: true});
}
handleCloseModal() {
this.setState({ showModal: false});
}
componentWillMount() {
ReactModal.setAppElement('body');
}
render() {
const { details } = this.props;
return (
<li className="Project">
<div onClick={this.handleOpenModal}>
<img className="Project-image" src={'projects/' + details.image} alt={details.name}/>
<div className="Project-overlay">
<p>{details.name}</p>
</div>
</div>
<div >
<ReactModal
isOpen={this.state.showModal}
contentLabel="This is my Modal"
shouldCloseOnOverlayClick={true}
onRequestClose={this.handleCloseModal}
>
<div className="modal-header">
<h3>{details.name}</h3>
</div>
<div className="modal-body">
<img className="Project-image" src={'projects/' + details.image} alt={details.name} />
<p className="desc-body">{details.desc}</p>
<p className="desc-body">{details.link}</p>
</div>
<div className="modal-footer">
{ details.havLink && <button className="button" href={details.link}>Click for Demo!</button> }
<button className="button" onClick={this.handleCloseModal}>Close Modal</button>
</div>
</ReactModal>
</div>
<div className="Project-tag">
<p>{details.tag}</p>
</div>
</li>
)
}
}
const props = {};
export default Project;
The issue is in the first line of the "modal-footer" class. This button will show if the havLink property is true. This data is being exported from another JS file. Everything else (image, description, modal title) all import correctly, even the link I set imports correctly but when the button is pushed nothing fires as I expected. I do not see any errors in my React dev tools either.
{details.link} as an href is not routing me to the specified link. The link will show up in the paragraph tag though (just to see if correct link populated).
Let me know if anything else is needed, I am hoping the solution is as simple as an incorrect binding. Thank you in advance!
<button> does not have the href attribute. You should be using an anchor element <a>. To the anchor you can pass whatever class or style you want to make it look like a button, but it's still an anchor element, not button.

Categories