5

I would like to add a StandaloneSearchBox, but I am unable to add it this is the problem I am receiving is this is the code I am using.

I did as shown in the documentation example but I am unable to get it working, and I can't find a working example.

I posted an example on codesanbox is the same code that I am using.

Link: codesandbox

enter image description here

Code:

import React, { useState, useRef, useCallback } from "react";
import {
  LoadScript,
  GoogleMap,
  DrawingManager,
  Polygon,
  Marker,
  OverlayView,
  StandaloneSearchBox
} from "@react-google-maps/api";
import Switch from "@material-ui/core/Switch";

import Paper from "@material-ui/core/Paper";
import MenuItem from "@material-ui/core/MenuItem";
import MenuList from "@material-ui/core/MenuList";

import "./styles.css";
const libraries = ["drawing"];

const options = {
  drawingControl: true,
  drawingControlOptions: {
    drawingModes: ["polygon"]
  },
  polygonOptions: {
    fillColor: `#2196F3`,
    strokeColor: `#2196F3`,
    fillOpacity: 0.5,
    strokeWeight: 2,
    clickable: true,
    editable: true,
    draggable: true,
    zIndex: 1
  }
};

class LoadScriptOnlyIfNeeded extends LoadScript {
  componentDidMount() {
    const cleaningUp = true;
    const isBrowser = typeof document !== "undefined"; // require('@react-google-maps/api/src/utils/isbrowser')
    const isAlreadyLoaded =
      window.google &&
      window.google.maps &&
      document.querySelector("body.first-hit-completed"); // AJAX page loading system is adding this class the first time the app is loaded
    if (!isAlreadyLoaded && isBrowser) {
      // @ts-ignore
      if (window.google && !cleaningUp) {
        console.error("google api is already presented");
        return;
      }

      this.isCleaningUp().then(this.injectScript);
    }

    if (isAlreadyLoaded) {
      this.setState({ loaded: true });
    }
  }
}

const defaultPaths = [];

export default function Map({ apiKey, center, paths = defaultPaths, point }) {
  const [state, setState] = useState({
    drawingMode: "polygon",
    pointSelect: null,
    checkedA: true
  });

  const noDraw = () => {
    setState(function set(prevState) {
      return Object.assign({}, prevState, {
        drawingMode: "maker"
      });
    });
  };

  const onPolygonComplete = React.useCallback(
    function onPolygonComplete(poly) {
      const polyArray = poly.getPath().getArray();
      let paths = [];
      polyArray.forEach(function(path) {
        paths.push({ lat: path.lat(), lng: path.lng() });
      });
      console.log("onPolygonComplete", paths);
      point(paths);
      noDraw();
      poly.setMap(null);
    },
    [point]
  );

  // Define refs for Polygon instance and listeners
  const polygonRef = useRef(null);
  const listenersRef = useRef([]);

  // Call setPath with new edited path
  const onEdit = useCallback(() => {
    if (polygonRef.current) {
      const nextPath = polygonRef.current
        .getPath()
        .getArray()
        .map(latLng => {
          return { lat: latLng.lat(), lng: latLng.lng() };
        });
      console.log("nextPath", nextPath);
      //setPath(nextPath);
      point(nextPath);
    }
  }, [point]);

  // Bind refs to current Polygon and listeners
  const onLoad = useCallback(
    polygon => {
      polygonRef.current = polygon;
      const path = polygon.getPath();
      listenersRef.current.push(
        path.addListener("set_at", onEdit),
        path.addListener("insert_at", onEdit),
        path.addListener("remove_at", onEdit)
      );
    },
    [onEdit]
  );

  // Clean up refs
  const onUnmount = useCallback(() => {
    listenersRef.current.forEach(lis => lis.remove());
    polygonRef.current = null;
  }, []);

  const deletePoint = key => {
    let pp = paths.filter((_, i) => i !== key);
    point(pp);
    setState(function set(prevState) {
      return Object.assign({}, prevState, {
        pointSelect: null
      });
    });
  };

  console.log("Map", paths);

  const handleChange = name => event => {
    setState({ ...state, [name]: event.target.checked });
  };

  const onPlacesChanged = al => console.log(al);

  return (
    <div className="App">
      Hi Web!!
      <LoadScriptOnlyIfNeeded
        id="script-loader"
        googleMapsApiKey={apiKey}
        libraries={libraries}
        language="it"
        region="us"
      >
        <GoogleMap
          mapContainerClassName="App-map"
          center={center}
          zoom={18}
          version="weekly"
        >
          <StandaloneSearchBox
            onLoad={onLoad}
            onPlacesChanged={onPlacesChanged}
          >
            <input
              type="text"
              placeholder="Customized your placeholder"
              style={{
                boxSizing: `border-box`,
                border: `1px solid transparent`,
                width: `240px`,
                height: `32px`,
                padding: `0 12px`,
                borderRadius: `3px`,
                boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
                fontSize: `14px`,
                outline: `none`,
                textOverflow: `ellipses`,
                position: "absolute",
                left: "50%",
                marginLeft: "-120px"
              }}
            />
          </StandaloneSearchBox>
          {state.checkedA && state.pointSelect !== null && (
            <OverlayView
              position={paths[state.pointSelect]}
              mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
            >
              <Paper>
                <MenuList>
                  <MenuItem disabled={true}>
                    Punto #{state.pointSelect}
                  </MenuItem>
                  <MenuItem onClick={() => deletePoint(state.pointSelect)}>
                    Elimina punto
                  </MenuItem>
                  <MenuItem>Modifica Punto</MenuItem>
                  <MenuItem
                    onClick={() => {
                      setState(function set(prevState) {
                        return Object.assign({}, prevState, {
                          pointSelect: null
                        });
                      });
                    }}
                  >
                    Annulla
                  </MenuItem>
                </MenuList>
              </Paper>
            </OverlayView>
          )}
          <div
            style={{
              backgroundColor: "#fff",
              borderRadius: 4,
              border: "1px solid #ccc",
              padding: 10,
              zIndex: 99999999,
              position: "absolute",
              top: "5px",
              right: "5px",
              width: "200px"
            }}
          >
            <b>Controls</b>
            <br />
            <br />
            <hr
              style={{
                //color: "#3794ff",
                backgroundColor: "#3794ff",
                height: 1
              }}
            />
            <Switch
              value="checkedA"
              inputProps={{ "aria-label": "secondary checkbox" }}
            />
            Show
            <br />
            <Switch
              checked={state.checkedA}
              value="checkedA"
              inputProps={{ "aria-label": "secondary checkbox" }}
              onChange={handleChange("checkedA")}
            />
            Show menu
          </div>
          {paths.length < 1 ? (
            <DrawingManager
              drawingMode={state.drawingMode}
              options={options}
              onPolygonComplete={onPolygonComplete}
            />
          ) : (
            <Polygon
              options={{
                fillColor: `#2196F3`,
                strokeColor: `#2196F3`,
                fillOpacity: 0.5,
                strokeWeight: 2
              }}
              // Make the Polygon editable / draggable
              editable
              draggable
              path={paths}
              // Event used when manipulating and adding points
              onMouseUp={onEdit}
              // Event used when dragging the whole Polygon
              onDragEnd={onEdit}
              onLoad={onLoad}
              onUnmount={onUnmount}
            />
          )}
          {paths.length > 0 &&
            paths.map((pos, key) => {
              return (
                <Marker
                  key={key}
                  label={"" + key}
                  position={pos}
                  onRightClick={pos => {
                    //let pp = paths.filter((_, i) => i !== key);
                    //point(pp);
                    console.log(key);
                    setState(function set(prevState) {
                      return Object.assign({}, prevState, {
                        pointSelect: key
                      });
                    });
                  }}
                  title={"[" + pos.lat + "," + pos.lng + "]"}
                  draggable
                  onDragEnd={pos => {
                    let obj = { lat: pos.latLng.lat(), lng: pos.latLng.lng() };
                    var copia = Object.assign([], paths);
                    copia[key] = obj;
                    point(copia);
                    if (state.pointSelect !== null)
                      setState(function set(prevState) {
                        return Object.assign({}, prevState, {
                          pointSelect: null
                        });
                      });
                  }}
                />
              );
            })}
        </GoogleMap>
      </LoadScriptOnlyIfNeeded>
    </div>
  );
}

1 Answer 1

7

@react-google-maps/api documentation states, for StandaloneSearchBox component:

Please do not forget to include "places" to libraries prop array on <LoadingScript />

In your example libraries variable could be updated to load places library:

const libraries = ["drawing", "places"];

Example

A minimal example demonstrates how to utilize StandaloneSearchBox component:

export default function Map(props) {
  function handleLoad() {}

  function hanldePlacesChanged() {}

  return (
    <LoadScript id="script-loader" googleMapsApiKey="" libraries={["places"]}>
      <GoogleMap
        zoom={5}
        center={{ lat: -25.0270548, lng: 115.1824598 }}
        id="map"
      >
        <StandaloneSearchBox
          onLoad={handleLoad}
          onPlacesChanged={hanldePlacesChanged}
        >
          <input
            type="text"
            placeholder="Customized your placeholder"
            style={{
              boxSizing: `border-box`,
              border: `1px solid transparent`,
              width: `240px`,
              height: `32px`,
              padding: `0 12px`,
              borderRadius: `3px`,
              boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
              fontSize: `14px`,
              outline: `none`,
              textOverflow: `ellipses`,
              position: "absolute",
              left: "50%",
              marginLeft: "-120px"
            }}
          />
        </StandaloneSearchBox>
      </GoogleMap>
    </LoadScript>
  );
}
Sign up to request clarification or add additional context in comments.

1 Comment

Seeing libraries={["places"]} helped unblock me, thanks. I was loading this via a const, e.g., const myLibraries = ['places'], but was always getting an error on the libraries={myLibraries} attribute.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.