Overriding the Google Maps API URL at runtime

In some cases, you may want to set the URL used to load the Google Maps API while your Ember app is actually running. For example, you could dynamically set the language parameter of the URL based on the language preferences of the current user.

To change the URL, overwrite the buildGoogleMapsURL function in the google-maps-api service. It receives all of the ember-google-maps configuration options.

/* app/services/google-maps-api.js */

import GoogleMapsAPIService from 'ember-google-maps/services/google-maps-api';

export default GoogleMapsAPIService.extend({
  buildGoogleMapsUrl(config) {
    let [language, region] = navigator.language.split('-');

    let src = `//maps.googleapis.com/maps/api/js?`
    let params = [`key=${config.key}`];

    if (language) { params.push(`language=${language}`); }

    if (region) { params.push(`region=${region}`); }

    return src + params.join('&');
  }
});

The URL can also depend on external, asynchronously loaded data. Using the localisation example, you could fetch the language preferences of the current user from an external database. While we wait for the database to respond, we can return the request promise and make sure it resolves with the correct URL for the API.

/* app/services/google-maps-api.js */

import GoogleMapsAPIService from 'ember-google-maps/services/google-maps-api';
import { inject as service } from '@ember/service';

export default GoogleMapsAPIService.extend({
  /**
   * Assume this is a service with a function `model` that loads the current
   * user.
   */
  currentUser: service(),

  buildGoogleMapsUrl(config) {
    return this.currentUser.model()
      .then(user => {
        return `//maps.googleapis.com/maps/api/js?key=${config.key}&language=${user.preferredLanguage}`;
      })
      .catch(error => {
        return `//maps.googleapis.com/maps/api/js?key=${config.key}`;
      });
  }
});
Custom components

Sometimes the built-in components just aren't enough. Or maybe they don't quite work work the way you want them to. That's where custom components come in. You can write your own map component and then use it the same way you'd use any of the built in ones. Custom components can be registered in your ember-cli-build.js.

const EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    'ember-google-maps': {
      customComponents: {
        // The key is the name you'd like to use in your templates.
        //
        // The value is the name of the component — the same name you'd pass
        // to the component helper.
        customMarker: 'the-name-of-the-component-to-use',
      },
      // An optional function to let you merge custom components declared by
      // other addons. This shouldn't be necessary in most cases, unless there
      // is a naming conflict.
      mergeCustomComponents(componentsByAddonName) {
        let components = {};

        for (([addonName, customComponents] of componentsByAddonName)) {
          Object.assign(components, customComponents);
        }

        return components;
      }
    },
  });

  return app.toTree();
};
<GMap @lat="51.508530" @lng="-0.076132" @zoom={{12}} as |map|>
  <map.customMarker @lat="51.508530" @lng="-0.076132" />
</GMap>

There aren't any guides on how to write your own components yet, so the best way to learn is to copy one of the built-in components and go from there.

Treeshaking

Ember apps that rely heavily on the addon ecosystem can eventually become quite large, negatively impacting load times. Addons, like this one, serve the needs of a diverse group of developers and include features that you may never need.

In your ember-cli-build.js, you can specify which components to include or exclude from the build using only and except.

Warning This is an advanced feature and may break your app. Manually excluding components from your build can be quite finicky and time-consuming. Use at your own peril.

const EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function(defaults) {
  let app = new EmberApp(defaults, {
    'ember-google-maps': {
      only: ['marker', 'info-window']
      // except: ['overlay']
    }
  });

  return app.toTree();
};
Performance issues

This addon relies heavily on Ember components. Components are what makes this addon simple and enjoyable to use. However, they come at a cost. Each component brings a bit of overhead that can eventually pile up into a heafty setup cost. Normally, this should not be an issue, apart from some extreme use-cases. If you intend to display thousands of markers, you should aim to create them in Javascript, or consider displaying fewer markers in the first place.