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

README not updated load() deprecated, importLibrary doesn't replace it 1-1 #837

Open
realgs opened this issue Mar 1, 2024 · 15 comments
Open
Labels
type: docs Improvement to the documentation for an API.

Comments

@realgs
Copy link

realgs commented Mar 1, 2024

Steps to reproduce

  1. Install js-api-loader 1.16.6, use steps from README to load google map script asynchronously - you get the IDE hint that load() is marked as deprecated, use importLibrary instead. ImportLibrary doesn't replace load(). Using load() everything works just fine but with the deprecation alert, using importLibrary it doesn't load maps.

Code example

            const loader = new Loader({
                libraries: ['places'],
                apiKey: this.apiKey,
            });
            loader.load().then((google) => {
                this.google = google;
                this.isLoading = false;
                this.isReady = true;
            });

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?

@realgs realgs added triage me I really want to be triaged. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. labels Mar 1, 2024
@wangela
Copy link
Member

wangela commented Mar 1, 2024

If you would like to upvote the priority of this issue, please comment below or react on the original post above with 👍 so we can see what is popular when we triage.

@realgs Thank you for opening this issue. 🙏
Please check out these other resources that might help you get to a resolution in the meantime:

This is an automated message, feel free to ignore.

@Schmell
Copy link

Schmell commented Mar 18, 2024

@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.

@usefulthink
Copy link
Contributor

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();

@owaisahmed5300
Copy link

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?

@owaisahmed5300
Copy link

@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.

@owaisahmed5300
Copy link

Relevent Issue: #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 };

@jmeinlschmidt
Copy link

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.

@jmeinlschmidt
Copy link

jmeinlschmidt commented Jul 30, 2024

Also, the load and loadCallback methods are being highlighted in both README file and Google Documentation, although being deprecated.

@Kocal
Copy link

Kocal commented Aug 10, 2024

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...

@mycarrysun
Copy link

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...

This should definitely be in this library, not something every caller has to implement themselves

@targetlucked69
Copy link

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...

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();
  }, []);

@usefulthink
Copy link
Contributor

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();
}, []);

@targetlucked69
Copy link

targetlucked69 commented Aug 28, 2024

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?

@usefulthink
Copy link
Contributor

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.

@mycarrysun
Copy link

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.

@usefulthink usefulthink added type: docs Improvement to the documentation for an API. and removed type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. triage me I really want to be triaged. labels Oct 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: docs Improvement to the documentation for an API.
Projects
None yet
Development

No branches or pull requests

9 participants