react-leaflet: Using a Component as a popup on a GeoJSON feature - javascript

My current use case is that I want to load in GeoJSON data, and render the points as markers on the map. This works fine.
My next step is to add a feature which displays a popup when the marker is clicked; this popup will include buttons which the user can press to call functions, which are passed to the component by the parent component. As such, the popup needs to be interactive.
Sadly, the only means of attaching a popup to a GeoJSON marker is to use the onEachFeature function, and binding the rendered HTML of the popup, like so:
const popupNode = <MapPopup marker={marker} closePopup={closePopup} />;
const popupText = ReactDOMServer.renderToString(popupNode);
marker.bindPopup(popupText);
Using renderToString means that the rendered popup is not interactive, and thus buttons and onClick listeners cannot be used and functions cannot be called.
The only other means I can think of is to render the popup completely independently of the map; intercept the popup event, get the associated marker, and render a component at the appropriate screen position, realigning it as the user drags the map around. This would be reinventing the wheel by completely abandoning Leaflet's existing popup code, and as such would be a massive pain.
However, I see no other means to bind a popup. Other solutions use the <Popup> component, but this requires using the <FeatureGroup> component which would mean abandoning the <GeoJSON> component.

I eventually ended up abandoning the GeoJSON component and using the Popup component.

Related

Best practice for making a popup window in React

In my React app, I want to create a popup window that renders a table with some data. However, I want to make it render in a separate browser window instance as opposed to a modal that is attached to the app's DOM. Most of my research has led me to third party component libraries that just render an in-DOM modal just in different ways. What is the best way to create my desired effect, where clicking the "Open" button creates a new browser window instance that renders the table component?
Thanks
hmm.. maybe try the window.open() syntax
https://developer.mozilla.org/en-US/docs/Web/API/Window/open

How to implement a generic react native backdrop?

I want to create a generic component that should detect required component View outside click (hide the View/dropdown, etc. when pressed outside). Basically it's for the Autocomplete Search Dropdown but I guess such functionality could be used in the future for other things.
The content should be dynamic and could be passed from any level of the app because such functionality is a common UX thing.
It shouldn't be modal that always render content at the screen center because a dropdown should be opened below its trigger, etc. So it should respect the initial component position. (In think to use onLayout/measure API of the initial position when passing the content into the Backdrop)
I researched a lot of resources and found that the one possible way is:
Create a TouchableWithoutFeedback layer (Backdrop) at the top level of the app.
make it fullscreen with/height
When dropdown is shown: render the Backdrop and onPress on it - close the dropdown & backdrop.
The main question is: How to pass a generic content into this Layer and save its relationship with the parent/props, re-render when needed, etc.?
Please, keep in mind, that the component which should pass content for this layer could be deep inside the app.
I guess it could be done via Context API, etc. but I'm not sure if it's the best possible way.
P.S. in the case of web it's a trivial task: create a fullscreen layer -> use a portal -> move content at the top level of the app -> render it at the required X\Y position and listen for the outside press.
I didn't expect that such functionality will be a problem in the case of RN.
Thanks for any help.

Angular - child component in new window has very odd behavior

I am using Angular's DomPortalHost to open a child component in a new browser window. It works for the most part.
Here is a working prototype of opening a child component in a new browser window:
https://stackblitz.com/edit/portalfun
I am able to pass data to and from child component - works great right?
Well.. when I have let's say, a map in the new browser window some of the map events seem to think the map exists in the original browser window. See:
https://www.youtube.com/watch?v=0387htqmXZw
Hilarity ensues:
I am able to click once in the new window to begin a selection (circle, etc) but not a second time. Using the view +/- controls seems to work fine. However, the map navigation/scrolling and the selection events think they are controlled from the original window.
The endgame for this little innovation project was to pass whatever data was selected in the map (syncing the grid you see in the background and the map). This works fine when I don't use DomPortalHost (that area below the grid is where the map was originally and it functions correctly).
I think that because *cdkPortal (see the stackblitz) is technically inside the original browser window:
<window *ngIf="showPortal" [dataFromParent]="dataToPass" (dataToParent)="this.onClosed($event)">
</window>
selector: 'window'...
<ng-container *cdkPortal>
<h1>Child component window</h1>
<div>{{dataFromParent}}</div>
<a class="btn-3" (click)="emitClose()">Close Window</a>
You can also close the parent window, or navigate to a different route. It will close the child window component.
</ng-container>
It's as if the map think's its been rendered in the original window, but is actually rendered in the new window.
The closest.. discovery that i've had was that some of the event handling has a [[Scope]] property set to the original window - not the new on. However I don't see how to overwrite this property.
If anyone has any ideas, resources, or a better approach please feel free to let me know. This is part of an innovation sprint, but it'd be cool to get it working as i'm sure it has a lot of use cases for others out there.
Imagine opening child components and passing data back and forth in new windows.. and not having to run a second cloned app or deal with the overheard of state management :)

Call method from sibling component using ReactJS

I have one ReactJS App which I reduced to the minimum as possible on the diagram below:
Side note: On this App I use Redux to manage state changes.
This App contains:
Component: UploadScreen with an image holder and a button. When that button is clicked, the user gets displayed a Popup Window which let him to pick an image from his device file system. Then that image is displayed on the image holder.
Component: AuxWidget which is a totally different component (needs to be separate) which also contains a button that when it is clicked it should popup the Select File window. I was thinking in something like triggering the click event of the first button.
Any idea on how to achieve that?
First I though about using Redux but I think that's not a too good idea because even though you can send messages with it from one component to another, that causes a render update and I don't want that.
Also, I was thinking on using jQuery but that's not the best approach when it comes to ReactJS.
Also, I thought about using the attribute: ref="foo" to get a reference to the other component but I think that's normally done when you want the interaction to be between parent and child components.
Also, I was thinking about EventEmmitter but I don't know if that's the best approach on this case (I'm using Redux to manage the state changes between components).
One of the best ways I can suggest using RxJS, you can create a Subject and pass it to your components. In one component you will need to subscribe to it and whenever you will call next on your subject from the second component, the other will be notified, so you can trigger open popup. You can even create your own implementation for this in case you don't want to add new library to your project.
The upload window could be triggered when a certain state in the app changes. The relevant state on the app could be changed from different places, like from AuxWidget and UploadScreen. That way they are not coupled with the upload window. They merely call a function that is passed to them and that function changes the state on the app and it will display the window.
If you have a shared component between two unrelated component I think it is best to lift that common component and let its state sit on a higher level.
If I understand things correctly, your primary concern is code-reuse as opposed to wanting to call a sibling method. Basically, you want a SelectFilePopup component that can be re-used (open/closed) cleanly. I think React Portals could be a good solution for this. I found a good example (https://github.com/Assortment/react-modal-component/blob/master/src/components/Modal.js) of how a Modal can be isolated into a component and be called anywhere in the codebase.
The usage of the Modal looks like this (copied and slightly modified from App.js in the github project above)
import Modal from './components/Modal';
<Modal><div>Click me to open Modal</div></Modal>
And the Modal component implementation (simplified)
render() {
return (
<Fragment>
<ModalTrigger
onOpen={this.onOpen}
/>
{isOpen &&
<ModalContent/>
}
</Fragment>
)
}
By default the Modal component shows a trigger (i.e button) when isOpen state is false. Once clicked, and isOpen switches to true, the ModalContent (i.e can be the FilePickerPopup) is dynamically created and attached to document body. You can check out the source code for more details. I think its a very clean solution to modals. So in your case, your code could end up looking something like this
UploadScreen.js
import FileSelectPopup from './components/FileSelectPopup';
<FileSelectPopup>{Upload Image}</FileSelectPopup>
AuxWidget.js
import FileSelectPopup from './components/FileSelectPopup';
<FileSelectPopup>{Upload Image or some other text}</FileSelectPopup>
So basically, AuxWidget doesn't even need to know about where the FileSelectPopup is located at. It's an independent component that can be called anywhere. The caveat is that the Modal implementation in the project I linked to is not a singleton (although it can be modified to be one). So if AuxWidget and UploadScreen are visible to the user at the same time, clicking both Upload Image buttons will create two instances of the Popup.
I would define the function in the parent component and pass it to both children as props

Binding a popup to a control

I have a LeafletJS control that renders a button. I want the button, when clicked, to open a popup on its position. So far I've tried calling the .bindPopup method on the control itself, which WebStorm seems to approve of, but the browser tells me that this method doesn't exist. What would be the preferred way to accomplish this task?
Leaflet controls don't implement the .bindPopup function.
Instead, you might find some luck looking at how the layers control works, it collapses/expands based on mouse events. You could potentially do something similar with your control, and show/hide your popup based on the click event and toggling a display: none css property.

Categories