Skip to content

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

Open
@lukas-siarny

Description

@lukas-siarny

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions