Open realgs opened 8 months ago
@realgs Thank you for opening this issue. 🙏 Please check out these other resources that might help you get to a resolution in the meantime:
google-maps
tagThis is an automated message, feel free to ignore.
@realgs Ya there is a new way to do it. I guess its more tree-shakeable or something
const addressSearchInput = document.querySelector('autocomplete')
const options = {
componentRestrictions: { country: 'ca' },
fields: ['formatted_address', 'address_components'],
}
// make a new loader here. NOTE there are no libraries here anymore
const loader = new Loader({
apiKey: PUBLIC_GOOGLE_MAPSAPI_KEY,
version: 'weekly'
})
// you can get anything from the places library here
const { Autocomplete, PlacesService, Place } = await loader.importLibrary('places')
//and to use one its something like this
const addressComplete = new Autocomplete(addressSearchInput , options)
addressComplete .addListener('place_changed', (place)=> console.log(place))
//repeat for other libraries
const { Map, TrafficLayer } = await loader.importLibrary('maps')
const { Marker } = await loader.importLibrary('marker')
I agree that documentation needs to reflect these changes.
I'd like to add that after loader.importLibrary()
you will also have access to the global google.maps
namespace as it was before after calling .load()
. So for example:
const loader = new Loader(loaderOptions);
await loader.importLibrary('maps');
// you can now access everything like before:
const map = new google.maps.Map();
Yes, indeed. with load we were able to load multiple libraries at once without any problem but with importLibrary we could only import 1 library at a time and in next recall we get below error.
Google Maps already loaded outside @googlemaps/js-api-loader.This may result in undesirable behavior as options and script parameters may not match.
Assume we need Map and Markers, what we suppose to do?
@Schmell Getting Warning
Google Maps already loaded outside @googlemaps/js-api-loader.This may result in undesirable behavior as options and script parameters may not match.
Relevent Issue: https://github.com/googlemaps/js-api-loader/issues/809
Fix: Promise.all() instead await for every importLibrary.
import { Loader } from '@googlemaps/js-api-loader';
const loader = new Loader({
apiKey: ''
version: 'weekly',
});
let libraries: any = null;
async function loadLibraries() {
if (!libraries) {
// not ideal to load all but just for an example.
libraries = await Promise.all([
loader.importLibrary('maps'),
loader.importLibrary('places'),
loader.importLibrary('marker'),
loader.importLibrary('geocoding'),
]);
}
return libraries;
}
const [{ Map }, { Autocomplete }, { AdvancedMarkerElement }, { Geocoder }] = await loadLibraries();
export { Map, AdvancedMarkerElement, Geocoder, Autocomplete };
I don't get the libraries
property in the constructor LoaderOptions
. Is this an obsolete option for loading additional libraries? Should it be deprecated in favour of .importLibrary()
? In what way are these two related?
const loader = new Loader({ libraries: ['maps'] });
vs
const loader = new Loader();
const { ... } = loader.importLibrary('maps');
Unfortunately, I couldn't find any satisfying answer in the docs.
Also, the load
and loadCallback
methods are being highlighted in both README file and Google Documentation, although being deprecated.
Hi folks, if you need to mimic the google.maps
structure without using the deprecated method loader.load()
, but by using loader.importLibrary()
, you can use the following code:
const google = {};
const libraries = ['core', 'maps', 'marker', /* ... */];
const librariesImplementations = await Promise.all(libraries.map((library) => loader.importLibrary(library)));
librariesImplementations.map((libraryImplementation, index) => {
const library = libraries[index];
// The following libraries are in a sub-namespace
if (['marker', 'places', 'geometry', 'journeySharing', 'drawing', 'visualization'].includes(library)) {
google.maps[library] = libraryImplementation;
} else {
google.maps = { ...(google.maps || {}), ...libraryImplementation };
}
});
By doing this way, you can have access to google.maps.LatLng
, google.maps.InfoWindow
, google.maps.marker.AdvancedMarkerElement
, etc...
Hi folks, if you need to mimic the
google.maps
structure without using the deprecated methodloader.load()
, but by usingloader.importLibrary()
, you can use the following code:const google = {}; const libraries = ['core', 'maps', 'marker', /* ... */]; const librariesImplementations = await Promise.all(libraries.map((library) => loader.importLibrary(library))); librariesImplementations.map((libraryImplementation, index) => { const library = libraries[index]; // The following libraries are in a sub-namespace if (['marker', 'places', 'geometry', 'journeySharing', 'drawing', 'visualization'].includes(library)) { google.maps[library] = libraryImplementation; } else { google.maps = { ...(google.maps || {}), ...libraryImplementation }; } });
By doing this way, you can have access to
google.maps.LatLng
,google.maps.InfoWindow
,google.maps.marker.AdvancedMarkerElement
, etc...
This should definitely be in this library, not something every caller has to implement themselves
Hi folks, if you need to mimic the
google.maps
structure without using the deprecated methodloader.load()
, but by usingloader.importLibrary()
, you can use the following code:const google = {}; const libraries = ['core', 'maps', 'marker', /* ... */]; const librariesImplementations = await Promise.all(libraries.map((library) => loader.importLibrary(library))); librariesImplementations.map((libraryImplementation, index) => { const library = libraries[index]; // The following libraries are in a sub-namespace if (['marker', 'places', 'geometry', 'journeySharing', 'drawing', 'visualization'].includes(library)) { google.maps[library] = libraryImplementation; } else { google.maps = { ...(google.maps || {}), ...libraryImplementation }; } });
By doing this way, you can have access to
google.maps.LatLng
,google.maps.InfoWindow
,google.maps.marker.AdvancedMarkerElement
, etc...
How do I apply this logic with my current code that uses load
?
useEffect(() => {
const init = async () => {
if (!apiKey) return;
try {
if ( !window.google || !window.google.maps || !window.google.maps.places ) {
await new Loader({ apiKey, ...{ libraries: ['places'], ...apiOptions }}).load();
}
initializeService();
} catch (error) {
if (typeof onLoadFailed === 'function') onLoadFailed(error);
}
}
if (apiKey) init();
else initializeService();
}, []);
modifying as little of the code as possible, that'd be something like this:
useEffect(() => {
const init = async () => {
if (!apiKey) return;
try {
if ( !window.google || !window.google.maps || !window.google.maps.places ) {
const loader = new Loader({ apiKey, apiOptions });
await Promise.all([
loader.importLibrary('maps'),
loader.importLibrary('places')
]);
}
initializeService();
} catch (error) {
if (typeof onLoadFailed === 'function') onLoadFailed(error);
}
}
if (apiKey) init();
else initializeService();
}, []);
modifying as little of the code as possible, that'd be something like this:
useEffect(() => { const init = async () => { if (!apiKey) return; try { if ( !window.google || !window.google.maps || !window.google.maps.places ) { const loader = new Loader({ apiKey, apiOptions }); await Promise.all([ loader.importLibrary('maps'), loader.importLibrary('places') ]); } initializeService(); } catch (error) { if (typeof onLoadFailed === 'function') onLoadFailed(error); } } if (apiKey) init(); else initializeService(); }, []);
So I dont have to do { libraries: ['places'], ...apiOptions }
anymore?
Also, does importLibrary
automatically going to attach a google
object to the window
?
Just noticed an error in this line: const loader = new Loader({ apiKey, apiOptions });
, it should have been const loader = new Loader({ apiKey, ...apiOptions });
Also, does importLibrary automatically going to attach a google object to the window?
Yes, this still works the same way with the async loader.
While I'm a fan of the new way to do it since I don't need to know which libraries to load beforehand, I'm mostly don't like having to use await
every time I need some class from the maps API. So I'll typically mix the old an new way.
So I dont have to do { libraries: ['places'], ...apiOptions } anymore?
I think you can do that as well, in that case you'd only need to e.g. loader.importLibrary('core')
or loader.importLibrary('maps')
instead of multiple importLibrary calls.
So I dont have to do { libraries: ['places'], ...apiOptions } anymore?
If you have libraries
in the apiOptions
object you'll need to loop through those and call importLibrary
for each one.
Steps to reproduce
Code example
I'd be happy to open a pull request to improve the project once you provide me with a solution. If load is deprecated what (and how) should be used instead?