Hiya! Is there an easy way to implement a search bar in my map through this package?
If not, are there plans to implement this?
Link to mapbox-gl example: https://www.mapbox.com/mapbox-gl-js/example/mapbox-gl-geocoder/
Hey @evanfrawley There is no plan to support this component, I believe this kind of react control should live in a different repository, If you work on this let me know I will make sure to reference it in the documentation.
Thank @alex3165 I'll see if I can implement it and will report back if I can get it working. Thanks for the quick response!
Update: I forked this repo and fiddled with the map.tsx file. I was able to implement the geocoder in a few changed in the code, but not without putting Mapbox's CSS file into the index.html. When I tried to import it within the Typescript, the npm run build command didn't like reading in the mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css file.
_Did you import the Mapbox CSS via the import statement from the library?_ The geocoder library wouldn't properly import with the line import * as MapboxGlGeocoder from 'mapbox-gl-geocoder/dist/mapbox-gl-geocoder.min'. The min.js doesn't seem to load in it's required CSS either.
Hey @evanfrawley, The css of mapbox gl is manually converted to a string https://github.com/alex3165/react-mapbox-gl/blob/master/src/constants/css.ts . Although I would suggest you to do the geocoder yourself without using the control provided by mapbox-gl-js, it is just a simple input after all then you would need to listen a change on it and request their geocoding API https://www.mapbox.com/api-documentation/#geocoding accordingly to get the data
In case anyone else ends up here, an easy fix is to create a geocoder component...
import { createElement, Component } from 'react';
import { Map } from 'mapbox-gl';
import PropTypes from 'prop-types';
import { accessToken } from './token';
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
import * as MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
class Geocoder extends Component {
static contextTypes = { map: PropTypes.object.isRequired };
context: {
map: Map;
};
componentDidMount() {
const { map } = this.context;
map.addControl(
new MapboxGeocoder({
accessToken
})
);
}
render() {
return null;
}
}
export default Geocoder;
And then include it in your map...
const MapBoxMap = ReactMapboxGl({ accessToken });
const Map = () =>
<MapBoxMap
style="..."
containerStyle={{
height: '100vh',
width: '100vw'
}}
>
<Layer type="symbol" id="marker" layout={{ 'icon-image': 'marker-15' }}>
<Feature coordinates={[-0.481747846041145, 51.3233379650232]} />
</Layer>
<Geocoder />
</MapBoxMap>
Edit: added context types as discussed below
Good job @bsouthga ! 馃憤
Hi @bsouthga I just came accross this example and was wondering if you could add how you passed the context through to the <Geocoder/>component. I'm just starting with the library and am having a little difficulty. Thanks!
Hey @taystu, the context should be available if you put the geocoder inside a Map component from this library, for example:
const MapBoxMap = ReactMapboxGl({ accessToken });
const Map = () =>
<MapBoxMap
containerStyle={{
height: '100vh',
width: '100vw'
}}
>
<Layer type="symbol" id="marker" layout={{ 'icon-image': 'marker-15' }}>
<Feature coordinates={[-0.481747846041145, 51.3233379650232]} />
</Layer>
<Geocoder />
</MapBoxMap>
Thanks for getting back to me @bsouthga I ended up fixing it by changing context: {
map: Map;
};
to
static contextTypes = {
map: PropTypes.object.isRequired
};
I suppose the former is typescript syntax? I'm not using typescript, but regardless thanks for the response.
I suppose
ah yeah good point! I forgot you need to add the context prop types.
Has anyone run into an issue where using
import * as MapboxGeocoder from '@mapbox/mapbox-gl-geocoder' throws an error saying could not find the module @mapbox/mapbox-gl-geocoder?
I don't know how mapbox export their module but have you tried
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder'
The module seems to be available:
https://unpkg.com/@mapbox/mapbox-gl-geocoder
However if you are using Typescript is seems that there is no type definitions for @mapbox/mapbox-gl-geocoder.
It's apparently not there by default. I needed to npm install mapbox-gl-geocoder and then it said it installed under the @mapbox namespace but it's actually not. I imported it from mapbox-gl-geocoder and it works.
the line of map.addControl is giving me an error if cannot read property of undefinded.
Console logging the context returns a blank object.
I also tried calling addControl directly onto Map but it says it's not a function.
Any help?
@tmerrr you might need to specify contextTypes as @taystu notes above.
Thank you, that was exactly it. Hadn't completely understood the above answer initially! Below solution to hopefully help others:
import { Component } from 'react';
import PropTypes from 'prop-types';
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
import * as MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
class Geocoder extends Component {
componentDidMount() {
const { map } = this.context;
map.addControl(
new MapboxGeocoder({
accessToken: 'your token'
})
);
}
render() {
return null;
}
static contextTypes = {
map: PropTypes.object.isRequired
};
}
export default Geocoder;
Hi, nice solution. But, could someone explain this syntax:
static contextTypes = {
map: PropTypes.object.isRequired
};
Is this a old react way of using context ?
@jerlam06 this stumped me when I came across it on another issue. It is the legacy context api, see https://reactjs.org/docs/legacy-context.html
Hey guys, thanks for all work. Really you help me a lot.
Jus a comment for people that are receiving this error:
could not find the module @mapbox/mapbox-gl-geocoder
for my side, the problem was solved after install "es6-promise" with:
yarn add es6-promise
Thank you so much @bsouthga for the response
However, MapboxGeocoder is the default export
Therefore I did
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
instead of
import * as MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
Only reason I mention this is for testing. This will allow you to mock the package using jest
jest.mock('@mapbox/mapbox-gl-geocoder');
Is it still working for you ? this.context is always undefined for me
i got it working as per @bsouthga suggestion above ^^ - But had to tweak to get it to stop erroring. Changed context to an object... not sure why that works. Not familiar with a lot of the Context/newer features of react.
So it went from
context: {
map: Map;
};
to
context = {
map: Map;
};
Bizarrely that worked.
One thing though - Can't seem to style the Geocoder component. Anyone know?
Is there a method to do this for React Native?
Currently, looking to add geocode functionality into my react native app.
Hi I'm trying to get this working and also getting the error: addControl undefined. I've implemented @tmerrr solution and the first one indicated here and can't get it to work. I know this thread is old but does anyone have any updates on this?
App.tsx:
```import React, { useRef, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
import ReactMapboxGl, { Layer, Feature } from 'react-mapbox-gl';
import { MapControl } from './MapControl';
import * as MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
const Map = ReactMapboxGl({
accessToken: 'xxx',
})
export const MapContext = React.createContext
function App() {
const mapRef = useRef
return (
export default App;
MapControl.tsx:
import { useContext } from 'react';
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
import { MapContext } from './App';
interface MapControlProps {
control: any
}
function MapControl(props: MapControlProps) {
const { mapRef } = useContext(MapContext)
const {map} = mapRef.current.state
map.addControl(props.control)
return null
}
export {MapControl}
```
In my case to solve for the addControl is undefined error this was enough:
const mapRef = useRef<any>(null)
or
const mapRef: any = useRef();
Indstead of only const mapRef = useRef();
Most helpful comment
In case anyone else ends up here, an easy fix is to create a geocoder component...
And then include it in your map...
Edit: added context types as discussed below