Komma igång - Hur man använder Google Maps API med angular-cli


Jag började nyligen med ng2. Så jag skapade ett projekt med angular-cli, sedan insåg jag att jag behöver några tredjepartsmoduler. Såsom Google Maps API, lodash, jquery...etc. Jag kan grunderna i Typescript, men hur använder jag dessa moduler i en Angular2-app? Jag vill också bara använda själva biblioteket, till exempel Google Maps API, inte någon befintlig ng2-modul/komponent som någon annan har gjort ovanpå Google Maps API - för lärandets skull.

Tidigare, med bara JS skulle jag inkludera js-filen och referera till API-dokumentationen för att veta vilka metoder jag skulle använda och bygga min app. Nu med Angular2, vilka steg bör jag ta för att göra samma sak?

Från min forskning verkar det som att jag först installerar de TypeScript-filer som behövs. Så för Google Maps gjorde jag npm install --save @types/google-maps. Nu, behöver jag importera detta modul i min Angular-app genom att inkludera det i app.module.ts? I imports-arrayen? Eller är det nu globalt tillgängligt?

En källa nämnde att installera det med npm och i min angular-cli.json inkludera en referens till det biblioteket i scripts-arrayen. så här:

"scripts": ['./node_modules/googlemaps/googemaps.min.js'],

Vilken metod ska användas för att installera Google Maps API? Jag skulle tänka att Typescript kanske är vägen att gå eftersom resten av Angular-appen kommer att skrivas i Typescript.

Nu i min app.component.ts vill jag skapa en enkel karta med hjälp av den typescript jag installerade. Hur skulle jag göra det? Google Maps API säger att man ska skapa en ny instans av kartan på följande sätt.

var map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: -34.397, lng: 150.644},
          scrollwheel: false,
          zoom: 8
        });

Hur skulle jag göra det med TypeScript-versionen av Google Maps som jag just installerade?

Skulle en TypeScript-version av Google Maps ha alla samma metoder som det ursprungliga API:et? Har TypeScripts för populära JS-bibliotek en dokumentationssajt jag kan referera till?

Svar #1

AGM-projektet som pekas ut av @Steve G. ger en bra utgångspunkt, men av någon anledning (som att hantera din egen begäranspolicy) kanske du vill skapa din egen typade wrapper. Så här gjorde jag det med Angular CLI:

Första steg :

npm i --save @types/googlemaps

För det andra, lägg till typerna i din tsconfig.app.json:

"types": ["googlemaps"]

Skriv äntligen ditt TypeScript:

//nothing to import here

//Replace this by anything without an ID_KEY
const getScriptSrc = (callbackName) => {
  return `https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=${callbackName}`;
}

export class GMapService {

  private map: google.maps.Map;
  private geocoder: google.maps.Geocoder;
  private scriptLoadingPromise: Promise<void>;

  constructor() {
        //Loading script
        this.loadScriptLoadingPromise();
        //Loading other components
        this.onReady().then(() => {
          this.geocoder = new google.maps.Geocoder();
        });
  }

  onReady(): Promise<void> {
    return this.scriptLoadingPromise;
  }

  initMap(mapHtmlElement: HTMLElement, options: google.maps.MapOptions): Promise<google.maps.Map> {
    return this.onReady().then(() => {
      return this.map = new google.maps.Map(mapHtmlElement, options);
    });
  }

  private loadScriptLoadingPromise() {
    const script = window.document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.defer = true;
    const callbackName: string = 'UNIQUE_NAME_HERE';
    script.src = getScriptSrc(callbackName);
    this.scriptLoadingPromise = new Promise<void>((resolve: Function, reject: Function) => {
      (<any>window)[callbackName] = () => { resolve(); };

      script.onerror = (error: Event) => { reject(error); };
    });
    window.document.body.appendChild(script);
  }

  /** Exemple of wrapped to promise API */
  geocode(address: string | google.maps.GeocoderRequest): Promise<google.maps.GeocoderResult[]> {
    return this.onReady().then(() => {
      this.geocoder.geocode(typeof address == "google.maps.GeocoderRequest" ? address: {address: address},
          (results: google.maps.GeocoderResult[], status: google.maps.GeocoderStatus) => {
            if(status == google.maps.GeocoderStatus.OK) {
              return results;
            } else {
              throw new Error(status.toString());
            }
      });
    });
  });

}

Och så kommer din kartkomponent att se ut så här:

@Component({
  selector: 'app-gmap-wrapper',
  template: '<div #map style="width:400px; height:300px">loading...</div>'
})
export class GMapWrapperComponent implements OnInit {
    @ViewChild('map') mapRef: ElementRef;

    constructor(private gmapService: GMapService) { }

    ngOnInit() {
      this.gmapService.initMap(this.mapRef.nativeElement, {
        center: {lat: 1234.1234, lng: 1234.1234},
        scrollwheel: true,
        zoom: 8
      });
    }
}

Denna kod borde vara bättre utan namespace google.maps som prefix för alla typer. Kanske några förslag?

Relaterade artiklar