gribnoysup / react-yandex-maps

Yandex Maps API bindings for React
MIT License
327 stars 116 forks source link

how to get Address by clicking to any location? #255

Closed JakhongirUrmonov closed 4 years ago

JakhongirUrmonov commented 4 years ago
import React, { useState} from 'react';
import { YMaps, Map, Placemark } from 'react-yandex-maps';
import Geocode from "react-geocode";

export const MapModel = (props) => {
    const [ addressName, setAddressName ] = useState(false);
    const [ addressError, setAddressError ] = useState(false);
    const [coords, setCoords] = useState([]);

  /**
     * Get the coordinates and get address using this coordinates 
     *
     * 
     */
    const getCoords = (e) =>{
        setCoords(e.get('coords'))
        Geocode.fromLatLng( e.get('coords')[0] , e.get('coords')[1] ).then(
            response => {
             const address = response.results[0].formatted_address,
              addressArray =  response.results[0].address_components,
              city = getCity( addressArray ),
              area = getArea( addressArray ),
              state = getState( addressArray );
             setAddressName(address)
            },
            error => {
             console.error(error);
            }
           );
    }
    const mapState = {
        center: [41.3110, 69.2405],
        zoom: 13
        };

        /**
     * Get the city and set the city input value to the one selected
     *
     * @param addressArray
     * @return {string}
     */
    const getCity = ( addressArray ) => {
        let city = '';
        for( let i = 0; i < addressArray.length; i++ ) {
        if ( addressArray[ i ].types[0] && 'administrative_area_level_2' === addressArray[ i ].types[0] ) {
        city = addressArray[ i ].long_name;
        return city;
        }
        }
    };
    /**
     * Get the area and set the area input value to the one selected
     *
     * @param addressArray
     * @return {string}
     */
    const getArea = ( addressArray ) => {
        let area = '';
        for( let i = 0; i < addressArray.length; i++ ) {
        if ( addressArray[ i ].types[0]  ) {
        for ( let j = 0; j < addressArray[ i ].types.length; j++ ) {
        if ( 'sublocality_level_1' === addressArray[ i ].types[j] || 'locality' === addressArray[ i ].types[j] ) {
            area = addressArray[ i ].long_name;
            return area;
        }
        }
        }
        }
   };
   /**
     * Get the address and set the address input value to the one selected
     *
     * @param addressArray
     * @return {string}
     */
    const getState = ( addressArray ) => {
        let state = '';
        for( let i = 0; i < addressArray.length; i++ ) {
        for( let i = 0; i < addressArray.length; i++ ) {
        if ( addressArray[ i ].types[0] && 'administrative_area_level_1' === addressArray[ i ].types[0] ) {
        state = addressArray[ i ].long_name;
        return state;
        }
        }
        }
    };

    return (
        <div  style={{marginTop: '50px'}}>
            <YMaps query={{
            apikey: 'API_KEY',
            load: "package.full",
            ns: "ymaps",
            }}>
            <Map
                state = {mapState}
                modules= {["geolocation", "geocode"]}
                onClick={e => getCoords(e)}
                width={852}
                >
                    <Placemark
                    geometry={{
                        type: 'Point',
                        coordinates: coords,
                      } }
                    properties={{
                        iconContent: addressName,

                      }}
                      options={{
                        // The placemark's icon will stretch to fit its contents.
                        preset: 'islands#blackStretchyIcon',
                        // The placemark can be moved.
                        draggable: true,
                      }}
                    /> 
            </Map>
        </YMaps>
        <div>
            <p>{addressName}</p>
        </div>
        </div>
    )
};
JakhongirUrmonov commented 4 years ago

I used Geocode library it works with the help of google map api, is there any ways to get same result without Geocode library?

mmarkelov commented 4 years ago

@CooperSky like so:

import React from "react";
import { YMaps, Map } from "react-yandex-maps";

const mapState = {
  center: [55.753994, 37.622093],
  zoom: 9
};

export default function App() {
  const ymaps = React.useRef(null);
  const placemarkRef = React.useRef(null);
  const mapRef = React.useRef(null);
  const [address, setAddress] = React.useState("");

  const createPlacemark = (coords) => {
    return new ymaps.current.Placemark(
      coords,
      {
        iconCaption: "loading.."
      },
      {
        preset: "islands#violetDotIconWithCaption",
        draggable: true
      }
    );
  };

  const getAddress = (coords) => {
    placemarkRef.current.properties.set("iconCaption", "loading..");
    ymaps.current.geocode(coords).then((res) => {
      const firstGeoObject = res.geoObjects.get(0);

      const newAddress = [
        firstGeoObject.getLocalities().length
          ? firstGeoObject.getLocalities()
          : firstGeoObject.getAdministrativeAreas(),
        firstGeoObject.getThoroughfare() || firstGeoObject.getPremise()
      ]
        .filter(Boolean)
        .join(", ");

      setAddress(newAddress);

      placemarkRef.current.properties.set({
        iconCaption: newAddress,
        balloonContent: firstGeoObject.getAddressLine()
      });
    });
  };

  const onMapClick = (e) => {
    const coords = e.get("coords");

    if (placemarkRef.current) {
      placemarkRef.current.geometry.setCoordinates(coords);
    } else {
      placemarkRef.current = createPlacemark(coords);
      mapRef.current.geoObjects.add(placemarkRef.current);
      placemarkRef.current.events.add("dragend", function () {
        getAddress(placemarkRef.current.geometry.getCoordinates());
      });
    }
    getAddress(coords);
  };

  return (
    <div className="App">
      <YMaps query={{ apikey: "your api key" }}>
        <Map
          modules={["Placemark", "geocode", "geoObject.addon.balloon"]}
          instanceRef={mapRef}
          onLoad={(ympasInstance) => (ymaps.current = ympasInstance)}
          onClick={onMapClick}
          state={mapState}
        />
        {address && (
          <div>
            <p>{address}</p>
          </div>
        )}
      </YMaps>
    </div>
  );
}
JakhongirUrmonov commented 4 years ago

Thanks a lot, I did something different

export const App = (props) => {
    const [ addressName, setAddressName ] = useState(false);

    const getCoords = e => {
        window.ymaps.geocode(e.get('coords')).then(res => {
            let firstGeoObject = res.geoObjects.get(0);
            setAddressName(firstGeoObject.getAddressLine())
        })

      };
    const mapState = {
        center: [41.3110, 69.2405],
        zoom: 13
        };

    return (
        <div>
            <YMaps query={{
            apikey: 'API_KEY,
            ns: "ymaps",
            }}>
            <Map
                state = {mapState}
                modules= {["geolocation", "geocode"]}
                onClick={e => getCoords(e)}
                >
                    <Placemark
                    geometry={{
                        type: 'Point',
                        coordinates: coords,
                      } }
                    properties={{
                        iconContent: addressName,   
                      }}
                      options={{
                        preset: 'islands#blackStretchyIcon',
                      }}
                    /> 
            </Map>
        </YMaps>
        <div>
        </div>
        </div>
    )
};
JakhongirUrmonov commented 4 years ago

which code is better and why? Please, could you explain to me?

mmarkelov commented 4 years ago

@CooperSky that's totally fine to use your code. I'm just not sure where you update your Placemark coordinates. Personally I don't like to use window to call ymaps methods.

JakhongirUrmonov commented 4 years ago

I got you, thanks one more time.