Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] TypeError: Cannot read properties of undefined (reading 'setAttribute') #424

Open
lukas-siarny opened this issue Jun 18, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@lukas-siarny
Copy link

lukas-siarny commented Jun 18, 2024

Description

Hello,

I am seeing this error in the console. It doesn't happen always. It happens only when the application runs for the first time and on the not allowed URL.

map_error2

This is the simplified code that we use:

import React, { useEffect, useState } from 'react'
import { Alert, Spin } from 'antd'
import { useTranslation } from 'react-i18next'
import { APIProvider, useApiIsLoaded, useApiLoadingStatus } from '@vis.gl/react-google-maps'

// dynamic imports
const StandaloneSearchBoxField = React.lazy(() => import('../atoms/StandaloneSearchBoxField'))
const MapContainer = React.lazy(() => import('./MapContainer'))

const MAP_KEY = window.__RUNTIME_CONFIG__?.VITE_GOOGLE_MAPS_API_KEY || 'SOME_RANDOM_STRING_AS_FALLBACK_FOR_UNDEFINED'

const AddressFields = () => {
	const { t } = useTranslation()

	const mapLoadingStatus = useApiLoadingStatus()
	const isLoaded = useApiIsLoaded()
	const isLoadingError = mapLoadingStatus === 'AUTH_FAILURE' || 'FAILED'
	const [mapError, setMapError] = useState<boolean>(isLoadingError)

	const [lat, setLat] = useState()
	const [lng, setLng] = useState()

	useEffect(() => {
		setMapError(isLoadingError)
	}, [isLoadingError])

	const onPlaceSelected = (place: google.maps.places.PlaceResult | null) => {
		if (!place) {
			return
		}

		console.log('place selected')
	}

	const onLocationChange = async ({ lat: newLat, lng: newLng }: { lat: number | undefined; lng: number | undefined }) => {
		if (newLat && newLng) {
			setLng(newLng)
			setLat(newLat)
		}
	}

	if (!isLoaded && !mapError) {
		return <Spin className={'w-full'} />
	}

	return mapError ? (
		<Alert message={t('loc:Google is currently unavailable.')} />
                 // NOTE: There are some fallback fields to enter the address manually
	) : (
		<div>
			<StandaloneSearchBoxField label={t('loc:Search')} required onPlaceSelected={onPlaceSelected} placeholder={t('loc:Search')} className={'mb-0 pb-0'} />
			<MapContainer onLocationChange={onLocationChange} lat={lat} lng={lng} />
		</div>
	)
}

const AddressFieldsProvider = () => {
	return (
		<APIProvider apiKey={MAP_KEY}>
			<AddressFields />
		</APIProvider>
	)
}

export default AddressFieldsProvider

and MapContainer component:

import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import cx from 'classnames'
import i18next from 'i18next'
import { Map, AdvancedMarker, MapCameraChangedEvent, MapMouseEvent } from '@vis.gl/react-google-maps'
import { MAP_CONFIG } from '../utils/enums'
import { getLanguageCode } from '../utils/intl'

type Props = {
	lat?: number
	lng?: number
	onLocationChange: (data: { lat: number | undefined; lng: number | undefined }) => void
	disabled?: boolean
}
// DOCS: https://visgl.github.io/react-google-maps/docs
// based on https://github.com/visgl/react-google-maps/blob/main/examples/autocomplete/src/autocomplete-custom.tsx
const MapContainer = (props: Props) => {
	const { i18n } = useTranslation()
	const { lng, lat, onLocationChange, disabled } = props

	const defaultMapLocation = MAP_CONFIG.locations[getLanguageCode(i18next.resolvedLanguage, i18next.language)]

	const position = lng && lat ? { lat, lng } : defaultMapLocation

	const [mapPosition, setMapPosition] = useState<google.maps.LatLng | null | google.maps.LatLngLiteral>(position)
	const [markerPosition, setMarkerPosition] = useState<google.maps.LatLng | null | google.maps.LatLngLiteral>(position)

	useEffect(() => {
		if (lat && lng) {
			const validLat = lat < MAP_CONFIG.maxLatitude && lat > MAP_CONFIG.minLatitude
			const validLng = lng < MAP_CONFIG.maxLongitude && lng > MAP_CONFIG.minLongitude
			if (validLat && validLng) {
				setMarkerPosition({ lat, lng })
				setMapPosition({ lat, lng })
			} else {
				setMarkerPosition(defaultMapLocation)
				setMapPosition(defaultMapLocation)
			}
		}
	}, [lat, lng, i18n, defaultMapLocation])

	const handleCameraChange = (ev: MapCameraChangedEvent) => {
		setMapPosition(ev.detail.center)
	}

	const onMarkerDragEnd = (e: google.maps.MapMouseEvent) => onLocationChange({ lng: e.latLng?.lng(), lat: e.latLng?.lat() })

	const onMapRightClick = (e: MapMouseEvent) => {
		if (disabled) {
			return
		}
		onLocationChange({ lng: e.detail.latLng?.lng, lat: e.detail.latLng?.lat })
	}

	return (
		<Map
			center={mapPosition}
			onCameraChanged={handleCameraChange}
			defaultZoom={MAP_CONFIG.defaultZoom}
			maxZoom={MAP_CONFIG.maxZoom}
			minZoom={MAP_CONFIG.minZoom}
			mapId={MAP_CONFIG.mapID}
			onContextmenu={onMapRightClick}
		>
			<AdvancedMarker draggable={!disabled} position={markerPosition} onDragEnd={onMarkerDragEnd} />
		</Map>
	)
}

export default MapContainer

The expected behavior is, that the mapLoadingStatus === 'AUTH_FAILURE' and user would see the fallback form. Is there something wrong with our implementation or is it the bug on your site?

Steps to Reproduce

Everything is already written in the bug description.

Environment

  • Library version: 1.0.0 and also tried 1.1.0
  • Google maps version: weekly
  • Browser and Version: Chrome 126.0.6478.61
  • OS: Windows 10

Logs

No response

@lukas-siarny lukas-siarny added the bug Something isn't working label Jun 18, 2024
@usefulthink
Copy link
Collaborator

So one important thing about this is that the loading status will always go from LOADING to LOADED before eventually changing to AUTH_FAILURE. The reason for this is that the API will only validate the key once it has been loaded (it maybe even waits until you actually start using it, not exactly sure how that works internally). Keep in mind that the key might very well be valid to create a map, but not configured to use places/autocomplete; or it could be valid but the API quota is exceeded.

Unfortunately, the Maps JavaScript API doesn't provide anything* to get more information about these cases (this would be something for the official issue-tracker if you care to open an issue there). (* the only thing we have, which is what's behind the AUTH_FAILED loading state in this library, is a global gm_authFailure function that gets called in case of a problem with the api-key)

Another thing I noticed is that the API will actually behave incorrectly (the error you're seeing is related to configuring the AdvancedMarker after it has been created) when the key-validation fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants