I have an element that has a Popover.
My Popover components gets a ref and know how to position itself:
const ref = useRef();
<div ref={ref}>Element</div>
<Popover targetRef={ref} >Popover element </Popover>
Now, I want to add a second Popover that will open under the first one:
Which ref I need to give to the second Popover? How can I achieve this behavior?
Related
How do i close a react bootstrap popover component in a react functional component? currently i am using a hack that closes the popover using the rootclose method and calling body.click on the button inside, however i feel this is not ideal, is there any way or method in the react bootstrap component or maybe by using refs with which i can achieve this?
**************following is how my component is structured right now *****
const setVisibility = (
<Popover id="popover-basic">
<Popover.Body className="px-0">
//code here
</Popover.Body>
</Popover>
);
const EditVisibility = () => (
<OverlayTrigger
trigger="click"
placement="bottom-end"
overlay={setVisibility}
rootClose
>
//code here
</OverlayTrigger>
);
and then I'm calling the EditVisibility component in the return method of my react functional component
Please look into the folling sandbox: https://codesandbox.io/s/close-popover-ytpze2
Introduce a show state to make the Popover controlled.
In Popover.Header you can define a closer button and set the show state to false on click
Write a callback function which toggle the Popover on button click ("onToggle" property of OverlayTrigger)
I have hundreds of objects rendered on the screen that are each wrapped in a <OverlayTrigger> (https://react-bootstrap.github.io/components/overlays/#overlaytrigger)
If these OverlayTriggers are displaying the same/similar text, is there a way I can just instantiate one and reuse that one, instead of rendering hundreds for each object that remain inactive until they're clicked/hovered over?
If you were able to use Overlay instead of OverlayTrigger you could do this by adding event handlers to the components that you want to trigger the overlay (e.g. onClick, onMouseOver/onMouseOut). The event handler would:
update the trigger to be the element that triggered the overlay (so the overlay is displayed alongside the element)
update the show state to ensure the overlay is displayed
The HTML would allow you to define a single Overlay element that can be used by multiple objects (in this case 4 buttons):
<div>
<Overlay target={target.current} show={show} placement="right">
<Tooltip id="button-tooltip">Simple tooltip</Tooltip>
</Overlay>
<Button onMouseOver={showOverlay} onMouseOut={showOverlay}>
Test
</Button>
<Button onMouseOver={showOverlay} onMouseOut={showOverlay}>
Test 2
</Button>
<Button onMouseOver={showOverlay} onMouseOut={showOverlay}>
Test 3
</Button>
<Button onMouseOver={showOverlay} onMouseOut={showOverlay}>
Test 4
</Button>
</div>
The show state and target ref would need to be introduced:
const [show, setShow] = useState(false); // Used to display the overlay
const target = useRef(null); // Used to store the reference to the HTML element that triggered the overlay
The showOverlay function would set the target ref to the HTML element that was clicked/hovered over, then set the flag to display the Overlay:
const showOverlay = (e) => {
target.current = e.target;
setShow(!show);
};
There's a working demo of this here.
I am trying to make an single selection in my app. I have a grid and inside it some images. When I clicked an image its parent which is a div background color change to red. I describe this event it is selected. I want to make deselect previous item when click any where. if clicked image is one of my item then new item should be selected and previous should be unselected. if clicked element is not one of my items just previus should be unselected. When I select an item then clicked one of the others it is working. However when I selected an item then click out of my items it is not working. In this stuation my prevClickedElement parameter refers to previous of previous clicked element. And I have no idea why state empty when update it in clickElement in context and in removePrevSelectedSquare in Piece component. Because of my app has multiple components and images I added to here. I am not sure this is the correct way. Because when I select an item component created items count times in this case 15. This is a performance problem?
I believe a good approach would be creating a component global state to save the current element unique id and creating a function to set the element id when it is clicked. After that you can create a function that reset this state whenever it is called and implement this function as an DOM event in a superior div, the parent of the images. Here is the ideia in form of a code snippet:
import React from 'react';
function Stackoverflow(props) {
const [selectedPicture, setSelectedPicture] = React.useState(null);
function resetSelectedPicture() {
setSelectedPicture(null)
}
return (
<div onClick={resetSelectedPicture}>
{pictures.map((picture, index) => {
const {id, src} = picture;
return (
<>
<img
src={src}
key={index}
id={id}
className={
selectedPicture.id === id
? 'selected-picture'
: 'unselected-picture'
}
onClick={setSelectedPicture(
() => picture
)}
/>
</>
);
})}
</div>
);
}
export default Stackoverflow;
So I have this modal that is wrapped with an entire background div. My issue is that I added a close function on the background, so no matter where I click, it will close the modal.
I would like to have the useRef only target the background div and not work if I click any of the children inside of it
Here is the code
const modalRef = useRef();
const closeModal = e => {
if (modalRef.current.contains(e.target)) {
setShowModal(false);
}
}
return (
<>
{showModal ? (
<Background onClick={closeModal} ref={modalRef}>
<animated.div style={animation}>
<ModalWrapper showModal={showModal}>
<div>hi</div>
<CloseModalButton
aria-label='Close modal'
// onClick={() => setShowModal(!showModal)}
/>
</ModalWrapper>
</animated.div>
</Background>
) : null}
</>
);
};
So right now the ref is attached to the background, but if I console.log(modalRef.current) it will show me the entire jsx with all my children divs inside, but I only want to target the outside div aka the background
So whenever I click outside of my modal it will close
Note: when I console.log(modalRef.current) this is what shows up in the console aka my entire JSX
I'm also using styled-components, so I only want to target the top div which I called Background but shows sc-bdnylx iEsAwc so I have no idea how to target it since it doesn't have any ids or classNames
I tried to add this console.log(modalRef.current.children[0]) but when I implemented it into my function, it didn't work properly. This console.log does only show the divs below my Background div, but I haven't found anything about targeting just the Background only
You don't actually need to use refs here. Just add onClick={e => e.stopPropagation()} to one of the divs inside Background, like on ModalWrapper. It'll stop the click from passing through.
Is there a way I can adjust a <Popover> element when fullscreen (Element.requestFullscreen())?
By default its DOM is placed on the body root, and for so, it doesn't show when the element that triggered it to appear is fullscreen.
Because of this, all menus I have on my fullscreen element are never shown until it leaves fullscreen.
You have to customize container prop of the Popover
component. container is the node of DOM which is Popover mounted to. By default it is document.body. That is why Popover is mounted behind the element that is in full-screen mode.
You have to set container node to the element which is going to be in full-screen mode.
props container of the Popover component:
const containerRef = useRef(null);
<div ref={containerRef}>
<button onClick={handleOpen}>open</button>
<Popover container={containerRef.current}>
...
</Popover>
</div>