Solvedangular google maps Using Geocoder with GoogleMapsAPIWrapper

I saw in issue #139 you are providing the ability to access google.maps object via the getMap() function, which I assume is now the getNativeMap() function in GoogleMapsAPIWrapper. I've also read that other people have gotten it to work, but I can't find any documentation or examples on how to use the GoogleMapsAPIWrapper and Geocoder.

import { Component, OnInit } from '@angular/core';
import { LocationService } from '../../core/location.service';
import { GoogleMapsAPIWrapper } from 'angular2-google-maps/core';

declare var google: any;

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {

  constructor(private wrapper: GoogleMapsAPIWrapper) {
    this.wrapper.getNativeMap().then((m) => {
      console.log("test");
    });

  }

  ngOnInit() {
    // var address = "1045 mission street san francisco";

    // var geocoder = new google.maps.Geocoder();

    // var result = "";

    // geocoder.geocode({ 'address': address }, (results, status) => {
    //   var latitude = results[0].geometry.location.lat();
    //   var longitude = results[0].geometry.location.lng();
    //   console.log("lat: " + latitude + ", long: " + longitude);
    // });
  }
}

Right now I can't even get the console.log to print out "test". I'm not sure why. Also would the m variable be the equivalent of google.maps? So that I can then use m.Geocoder()?

I'm also not sure if I'm importing the GoogleMapsAPIWrapper correctly. Currently I'm importing it in the core.module, since the Angular 2 guidelines say to have services be in the core.module. "sebm-google-map" works for me without any issues, so I think the AgmCoreModule is imported correctly, I'm just not sure about how to use GoogleMapsAPIWrapper.

import {
    ModuleWithProviders, NgModule,
    Optional, SkipSelf
} from '@angular/core';

import { AgmCoreModule, GoogleMapsAPIWrapper } from 'angular2-google-maps/core';


import { FirebaseService, FirebaseServiceConfig } from './firebase.service';
import { LocationService } from './location.service';


@NgModule({
    imports: [AgmCoreModule.forRoot({apiKey: "blahblahapikey"}),],
    declarations: [],
    exports: [AgmCoreModule],
    providers: [FirebaseService, LocationService, GoogleMapsAPIWrapper]
})
export class CoreModule {

    constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
        if (parentModule) {
            throw new Error(
                'CoreModule is already loaded. Import it in the AppModule only');
        }
    }

    static forRoot(config: FirebaseServiceConfig): ModuleWithProviders {
        return {
            ngModule: CoreModule,
            providers: [
                { provide: FirebaseServiceConfig, useValue: config }
            ]
        };
    }
}

I've been able to get google.maps.Geocoder() to work via GMap from PrimeNG, but sometimes I get google is not defined errors. So I'm trying to use Sebastian's google map instead.

43 Answers

✔️Accepted Answer

How about this -

import { Injectable, NgZone } from '@angular/core';
import { GoogleMapsAPIWrapper } from 'angular2-google-maps/core';
import { MapsAPILoader } from 'angular2-google-maps/core';
import { Observable, Observer } from 'rxjs';

declare var google: any;

@Injectable()
export class GMapsService extends GoogleMapsAPIWrapper{ 
    constructor(private __loader: MapsAPILoader, private __zone: NgZone) {
        super(__loader, __zone);
    }

    getLatLan(address: string) {
        console.log('Getting Address - ', address);
        let geocoder = new google.maps.Geocoder();
        return Observable.create(observer => {
            geocoder.geocode( { 'address': address}, function(results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    observer.next(results[0].geometry.location);
                    observer.complete();
                } else {
                    console.log('Error - ', results, ' & Status - ', status);
                    observer.next({});
                    observer.complete();
                }
            });
        })
    }
}

Other Answers:

Working example of geocoding service https://stackblitz.com/edit/angular-google-maps-demo-geocoding based on examples listed here.

I got it working with agm combining answers of @vintesh, @FabioBentoLuiz and @neilpennell.

google-maps.service.ts:

import { Injectable, NgZone } from '@angular/core';
import { GoogleMapsAPIWrapper } from '@agm/core';
import { MapsAPILoader } from '@agm/core';
import { Observable, Observer } from 'rxjs';

declare var google: any;

@Injectable()
export class GMapsService extends GoogleMapsAPIWrapper{ 
    constructor(private __loader: MapsAPILoader, private __zone: NgZone) {
        super(__loader, __zone);
    }

    getLatLan(address: string) {
        console.log('Getting Address - ', address);
        let geocoder = new google.maps.Geocoder();
        return Observable.create(observer => {
            geocoder.geocode( { 'address': address}, function(results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    observer.next(results[0].geometry.location);
                    observer.complete();                    
                } else {
                    console.log('Error - ', results, ' & Status - ', status);
                    observer.next({});
                    observer.complete();
                }
            });
        })
    }
}

shops.component.ts:

import { Component, NgZone } from '@angular/core';
import { GMapsService } from '../services/google-maps.service'

@Component({  
  templateUrl: 'shops.component.html',
  styleUrls: ['shops.component.css']
})

export class ShopsComponent {  
  constructor(private gMapsService: GMapsService, private __zone: NgZone ){}
  lat:number
  lng:number

  getAddress() {
    this.gMapsService.getLatLan('Andorra')
      .subscribe(
        result => {
            this.__zone.run(() => {
                this.lat = result.lat();
                this.lng = result.lng();
            })
        },
        error => console.log(error),
        () => console.log('Geocoding completed!')
      );
  }
}

shops.component.html:

<agm-map [latitude]="lat" [longitude]="lng"></agm-map>

shops.component.css:

agm-map {
    height: 300px;
}

Thanks guys!

Hello "google undefined" friends. Did you try the tip of our colleague @gnujeremie?
This is working for me (Angular 2.2.3):

import { Injectable } from '@angular/core';
import { MapsAPILoader } from 'angular2-google-maps/core';
import { Observable } from 'rxjs/Observable';

declare var google: any;

@Injectable()
export class MapsService {
    constructor(private __loader: MapsAPILoader) {

    }

    getGeocoding(address: string) {
        return Observable.create(observer => {
            try {
                //at this point the variable google may be still undefined (google maps scripts still loading)
                //so load all the scripts, then...
                this.__loader.load().then(() => {
                    let geocoder = new google.maps.Geocoder();
                    geocoder.geocode({ address }, (results, status) => {

                        if (status === google.maps.GeocoderStatus.OK) {
                            const place = results[0].geometry.location;
                            observer.next(place);
                            observer.complete();
                        } else {
                            console.error('Error - ', results, ' & Status - ', status);
                            if (status === google.maps.GeocoderStatus.ZERO_RESULTS) {
                                observer.error('Address not found!');
                            }else {
                                observer.error(status);
                            }
                            
                            observer.complete();
                        }
                    });
                });
            } catch (error) {
                observer.error('error getGeocoding' + error);
                observer.complete();
            }

        });
    }
}

If you just need Geocoder(), you don't need to use getNativeMap().

I'm importing MapsAPILoader, so I can use it this way :

this.mapsAPILoader.load().then(() => {
    console.log('google script loaded');
    var geocoder = new google.maps.Geocoder();
});

But if you want to get the native map, you TestComponent must be loaded inside the google map component :

<sebm-google-map [latitude]="lat" [longitude]="lng">
    <app-test></app-test>
</sebm-google-map>

and you have to be sure that your instance of GoogleMapsAPIWrapper inside TestComponent is the same instance used by SebmGoogleMap

More Issues: