Reputation: 2606
React-leaflet nicely provides the ability to put content within a Popup
of a Marker.
For instance in my example:
<Marker position={[item.lat, item.lng]} key={item.machineid}>
<Popup maxWidth={720}>
<ItemGrid machineid={item.machineid}
username={this.props.username}/>
</Popup>
</Marker>
However if this content is too big, it can be unwieldly, especially on mobile. I would like to have a (bootstrap) Modal interface activate on the click of the Marker. Is there way to do that in react-leaflet?
Upvotes: 16
Views: 27687
Reputation: 5717
For people who want pass an argument, you should use:
<Marker
position={[50.5, 30.5]}
data="FooBar"
eventHandlers={{
click: (e) => {
console.log(e.target.options.data); // will print 'FooBar' in console
},
}}
/>
Upvotes: 2
Reputation: 2235
Update: Evented behavior#
Use the eventHandlers listener function inside the Marker component:
<Marker
position={[50.5, 30.5]}
eventHandlers={{
click: (e) => {
console.log('marker clicked', e)
},
}}
/>
Upvotes: 52
Reputation: 3212
As per the react-leaflet docs,
Leaflet exposes its own events, different from React. You can listen to them using React-Leaflet by adding a callback to a property prefixed by on. Ex:
<Map onMoveend={this.handleMoveend}>...</Map>
.Check 🍃 Leaflet's documentation for the events associated to each component.
Therefore we can use Leaflet's native onClick DOM event.
With react-leaflet
, it would look something like this:
import React, { Component } from "react"
import { Map as LeafletMap, TileLayer, Marker } from "react-leaflet"
class Map extends Component {
handleClick = event => {
const { lat, lng } = event.latlng
console.log(`Clicked at ${lat}, ${lng}`)
}
render () {
return (
<LeafletMap center={[52.5134, 13.4225]} zoom={13}>
<TileLayer attribution={attribution} url={url}>
<Marker
position={[52.5134, 13.4225]}
onClick={this.handleClick} // <-- call handleClick()
/>
</TileLayer>
</LeafletMap>
)
}
}
export default Map
Upvotes: 3
Reputation: 2606
I found a kind of hack to perform an arbitrary action on tapping on the Marker. (1)Keep the popup, but have it's contents do whatever you like (e.g. Open a modal by defaut) and (2) Hide the popup's container div with CSS.
In my case it looked like this: Map View, remains unchanged:
<Marker position={[item.lat, item.lng]} key={item.machineid}>
<Popup maxWidth={720}>
<ItemGrid machineid={item.machineid}
username={this.props.username}/>
</Popup>
</Marker>
Then ItemGrid which was previously in a pop changes to include a modal. (Here we are using reactstrap components and set the modal to true
whnn the component mounts.) :
class ItemGrid extends Component {
constructor(props){
super(props);
this.state = {modal:false}
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
modal: !this.state.modal
});
}
componentDidMount() {
this.setState({modal:true})
}
render() {
return (
<div>
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
<ModalHeader toggle={this.toggle}>Modal Header</ModalHeader>
<ModalBody>
{ContentThatWasPreviouslyInPopup}
</ModalBody>
</Modal>
</div>
And Finally in leaflet CSS:
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
padding: 8px 8px 0 0;
text-align: center;
width: 0px;
height: 0px;
font: 0px/0px Tahoma, Verdana, sans-serif; //DANGEROUS HACK
color: #c3c3c3;
text-decoration: none;
font-weight: bold;
background: transparent;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
width: 0px // DANGEROUS HACK
}
Upvotes: 1