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

Using Geocoder with GoogleMapsAPIWrapper #689

Open
RedFour opened this Issue Oct 1, 2016 · 37 comments

Comments

@RedFour

RedFour commented Oct 1, 2016

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.

@gnujeremie

This comment has been minimized.

Show comment
Hide comment
@gnujeremie

gnujeremie Oct 2, 2016

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

gnujeremie commented Oct 2, 2016

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

@RedFour

This comment has been minimized.

Show comment
Hide comment
@RedFour

RedFour Oct 3, 2016

@gnujeremie thx for the tip to use MapsAPILoader. How do I go about importing it? Did you import it along with AgmCoreModule?

RedFour commented Oct 3, 2016

@gnujeremie thx for the tip to use MapsAPILoader. How do I go about importing it? Did you import it along with AgmCoreModule?

@gnujeremie

This comment has been minimized.

Show comment
Hide comment
@gnujeremie

gnujeremie Oct 3, 2016

No, AgmCoreModule is imported only in my module using google map.
I directly import import { MapsAPILoader } from 'angular2-google-maps/core'; in my service.

gnujeremie commented Oct 3, 2016

No, AgmCoreModule is imported only in my module using google map.
I directly import import { MapsAPILoader } from 'angular2-google-maps/core'; in my service.

@vintesh

This comment has been minimized.

Show comment
Hide comment
@vintesh

vintesh Oct 10, 2016

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

vintesh commented Oct 10, 2016

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();
                }
            });
        })
    }
}
@FabioBentoLuiz

This comment has been minimized.

Show comment
Hide comment
@FabioBentoLuiz

FabioBentoLuiz Dec 9, 2016

In addition to the solution presented by @vintesh I had to update the lat and lng inside the NgZone to update the map.

clickSearchAddress() {
        this._mapsService.getLatLan(this.model.address)
            .subscribe(
            result => {
                // needs to run inside zone to update the map
                this._zone.run(() => {
                    this.model.lat = result.lat();
                    this.model.lng = result.lng();
                });
            },
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );
    }

FabioBentoLuiz commented Dec 9, 2016

In addition to the solution presented by @vintesh I had to update the lat and lng inside the NgZone to update the map.

clickSearchAddress() {
        this._mapsService.getLatLan(this.model.address)
            .subscribe(
            result => {
                // needs to run inside zone to update the map
                this._zone.run(() => {
                    this.model.lat = result.lat();
                    this.model.lng = result.lng();
                });
            },
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );
    }
@slooker

This comment has been minimized.

Show comment
Hide comment
@slooker

slooker Jan 4, 2017

I still run into problems when trying to use the geocoder. Here's my code.

import { MapsAPILoader } from 'angular2-google-maps/core';
constructor(public mapsApiLoader: MapsAPILoader) {
    this.mapsApiLoader.load().then(() => {
      console.log('google script loaded');
      this.geocoder = new google.maps.Geocoder();
      console.log(this.geocoder);
    });

I get two errors:

Cannot find name 'google'.
and
rollup failed: 'MapsAPILoader' is not exported by node_modules/angular2-google-maps/core/index.js (imported by src/services/location.ts). For help fixing this error see https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module

slooker commented Jan 4, 2017

I still run into problems when trying to use the geocoder. Here's my code.

import { MapsAPILoader } from 'angular2-google-maps/core';
constructor(public mapsApiLoader: MapsAPILoader) {
    this.mapsApiLoader.load().then(() => {
      console.log('google script loaded');
      this.geocoder = new google.maps.Geocoder();
      console.log(this.geocoder);
    });

I get two errors:

Cannot find name 'google'.
and
rollup failed: 'MapsAPILoader' is not exported by node_modules/angular2-google-maps/core/index.js (imported by src/services/location.ts). For help fixing this error see https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module

@gnujeremie

This comment has been minimized.

Show comment
Hide comment
@gnujeremie

gnujeremie Jan 4, 2017

@slooker you need to add declare var google: any; before the declaration of your constructor.

gnujeremie commented Jan 4, 2017

@slooker you need to add declare var google: any; before the declaration of your constructor.

@slooker

This comment has been minimized.

Show comment
Hide comment
@slooker

slooker Jan 4, 2017

@gnujeremie That solves the google undefined problem, but it still tells me that MapsAPILoader isn't exported by angular2-google-maps.

slooker commented Jan 4, 2017

@gnujeremie That solves the google undefined problem, but it still tells me that MapsAPILoader isn't exported by angular2-google-maps.

@kumar-ravi007

This comment has been minimized.

Show comment
Hide comment
@kumar-ravi007

kumar-ravi007 Jan 25, 2017

@slooker I too faced the same issue and MapsAPILoader error is coming because "node_modules/angular2-google-maps/core/index.js" do not export MapsAPILoader .I have solved this issue. Insert following code in "node_modules/angular2-google-maps/core/index.js" file as follows :

var core_module_2 = require('./core.umd'); exports.MapsAPILoader = core_module_2.MapsAPILoader;

This works for me. Hope this will work for you also.

kumar-ravi007 commented Jan 25, 2017

@slooker I too faced the same issue and MapsAPILoader error is coming because "node_modules/angular2-google-maps/core/index.js" do not export MapsAPILoader .I have solved this issue. Insert following code in "node_modules/angular2-google-maps/core/index.js" file as follows :

var core_module_2 = require('./core.umd'); exports.MapsAPILoader = core_module_2.MapsAPILoader;

This works for me. Hope this will work for you also.

@DoubleExposure

This comment has been minimized.

Show comment
Hide comment
@DoubleExposure

DoubleExposure Jun 6, 2017

Do you guys have a working version? I get my addresses from a database and I need their coordinates in order to build a marker cluster. GeoCoder is defined in the constructor but is not accessible via the nginit method.

DoubleExposure commented Jun 6, 2017

Do you guys have a working version? I get my addresses from a database and I need their coordinates in order to build a marker cluster. GeoCoder is defined in the constructor but is not accessible via the nginit method.

@DoubleExposure

This comment has been minimized.

Show comment
Hide comment
@DoubleExposure

DoubleExposure Jun 7, 2017

VinTesh, why does the service you listed say that google is undefined? What is the proper way tos et this up? Thanks

DoubleExposure commented Jun 7, 2017

VinTesh, why does the service you listed say that google is undefined? What is the proper way tos et this up? Thanks

@nichovski

This comment has been minimized.

Show comment
Hide comment
@nichovski

nichovski Jun 17, 2017

I'm facing the same google undefined problem. Any suggestions?

I'm using "@agm/core": "^1.0.0-beta.0"

Thanks

nichovski commented Jun 17, 2017

I'm facing the same google undefined problem. Any suggestions?

I'm using "@agm/core": "^1.0.0-beta.0"

Thanks

@daBishMan

This comment has been minimized.

Show comment
Hide comment
@daBishMan

daBishMan Jun 19, 2017

getCurrentPositionSuccessCallBack(position: Position) {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;

    const latLng: LatLngLiteral = {
      lat: latitude,
      lng: longitude
    };

    const geoCoder = new google.maps.Geocoder();

    geoCoder.geocode({ "location": latLng }, (results, status) => {

is my code and it works fine, but I am trying to write a unit test

fit('onGeoLocate should set the right location', () => {

    spyOn(navigator.geolocation, 'getCurrentPosition').and.callFake(function () {
      const position = { coords: { latitude: 32, longitude: -96 } };
      arguments[0](position);
    });
    component.onGeoLocate();

but it fails with

 Failed: google is not defined

Help please?

daBishMan commented Jun 19, 2017

getCurrentPositionSuccessCallBack(position: Position) {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;

    const latLng: LatLngLiteral = {
      lat: latitude,
      lng: longitude
    };

    const geoCoder = new google.maps.Geocoder();

    geoCoder.geocode({ "location": latLng }, (results, status) => {

is my code and it works fine, but I am trying to write a unit test

fit('onGeoLocate should set the right location', () => {

    spyOn(navigator.geolocation, 'getCurrentPosition').and.callFake(function () {
      const position = { coords: { latitude: 32, longitude: -96 } };
      arguments[0](position);
    });
    component.onGeoLocate();

but it fails with

 Failed: google is not defined

Help please?

@FabioBentoLuiz

This comment has been minimized.

Show comment
Hide comment
@FabioBentoLuiz

FabioBentoLuiz Jun 22, 2017

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

        });
    }
}

FabioBentoLuiz commented Jun 22, 2017

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

        });
    }
}
@DoubleExposure

This comment has been minimized.

Show comment
Hide comment
@DoubleExposure

DoubleExposure Jun 23, 2017

Fabio, can you provide a sample of how this is called and used?

DoubleExposure commented Jun 23, 2017

Fabio, can you provide a sample of how this is called and used?

@neilpennell

This comment has been minimized.

Show comment
Hide comment
@neilpennell

neilpennell Jul 23, 2017

@DoubleExposure assuming you have a constructor like this

constructor(private ms: MapsService) {
}

you can call this in your code

this.ms.getGeocoding( '10 10th Street NE, Atlanta, GA 30309' ).subscribe(function (x) {
console.log(x.toString());
});

neilpennell commented Jul 23, 2017

@DoubleExposure assuming you have a constructor like this

constructor(private ms: MapsService) {
}

you can call this in your code

this.ms.getGeocoding( '10 10th Street NE, Atlanta, GA 30309' ).subscribe(function (x) {
console.log(x.toString());
});

@Canadadry

This comment has been minimized.

Show comment
Hide comment
@Canadadry

Canadadry Oct 27, 2017

@FabioBentoLuiz @gnujeremie Hi 've tried your code and it's working great. Except the first call which allways fail. I've tried to make a first call in an ngOnInit but it does not seems to work.

Here my usage attempt

import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { Router, ActivatedRoute, ParamMap} from '@angular/router';

import 'rxjs/add/operator/switchMap';
import { Observable } from 'rxjs/Observable';

import { Place } from './../place';
import { PlaceService } from './../place.service';
import { MapsService } from './map.service';
import { AlertService } from './../AlertComponent/alert.service';


@Component({
  selector: 'app-detailview',
  templateUrl: './detail.component.html',
  styleUrls: ['./detail.component.css'], 
})


export class DetailComponent implements OnInit {

	place: Place;  
	lat: number = 51.678418;
  	lng: number = 7.809007;

	ngOnInit() {
		let selectedId = this.route.paramMap.subscribe(
				(params: ParamMap)  =>	this.place = this.placeService.getPlaceById(+params.get('id'))
			);
		this.maps.getGeocoding('')
            .subscribe(
            result => console.log(result),
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );
	}

	constructor(private placeService: PlaceService,
				private route       : ActivatedRoute,
				private location    : Location,
				private alert       : AlertService,
				private maps        : MapsService) {
	}

	clickSearchAddress() {
		let address = this.place.name + " " + this.place.address + " " + this.place.city + " " + this.place.postalCode;
        this.maps.getGeocoding(address)
            .subscribe(
            result => {
                    this.lat = result.lat();
                    this.lng = result.lng();
            },
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );
    }

	back(){
		this.location.back();
	}

Canadadry commented Oct 27, 2017

@FabioBentoLuiz @gnujeremie Hi 've tried your code and it's working great. Except the first call which allways fail. I've tried to make a first call in an ngOnInit but it does not seems to work.

Here my usage attempt

import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { Router, ActivatedRoute, ParamMap} from '@angular/router';

import 'rxjs/add/operator/switchMap';
import { Observable } from 'rxjs/Observable';

import { Place } from './../place';
import { PlaceService } from './../place.service';
import { MapsService } from './map.service';
import { AlertService } from './../AlertComponent/alert.service';


@Component({
  selector: 'app-detailview',
  templateUrl: './detail.component.html',
  styleUrls: ['./detail.component.css'], 
})


export class DetailComponent implements OnInit {

	place: Place;  
	lat: number = 51.678418;
  	lng: number = 7.809007;

	ngOnInit() {
		let selectedId = this.route.paramMap.subscribe(
				(params: ParamMap)  =>	this.place = this.placeService.getPlaceById(+params.get('id'))
			);
		this.maps.getGeocoding('')
            .subscribe(
            result => console.log(result),
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );
	}

	constructor(private placeService: PlaceService,
				private route       : ActivatedRoute,
				private location    : Location,
				private alert       : AlertService,
				private maps        : MapsService) {
	}

	clickSearchAddress() {
		let address = this.place.name + " " + this.place.address + " " + this.place.city + " " + this.place.postalCode;
        this.maps.getGeocoding(address)
            .subscribe(
            result => {
                    this.lat = result.lat();
                    this.lng = result.lng();
            },
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );
    }

	back(){
		this.location.back();
	}

@FabioBentoLuiz

This comment has been minimized.

Show comment
Hide comment
@FabioBentoLuiz

FabioBentoLuiz Oct 27, 2017

Hi @Canadadry ,
How the first call fails? Are you using the MapsAPILoader?

FabioBentoLuiz commented Oct 27, 2017

Hi @Canadadry ,
How the first call fails? Are you using the MapsAPILoader?

@Canadadry

This comment has been minimized.

Show comment
Hide comment
@Canadadry

Canadadry Oct 27, 2017

My map is supposed to center on the address.
So I have mapped the clickSearchAddress() on a button and It only moves the map on the second click. On the first click I only have the log : Geocoding completed!
Stranger thing, I have put the clickSearchAddress() call on the subscribe of route.paramMapin ngOnInit and there the function work on the first call.

I have tried waiting before starting to click to be sure google map script are loaded but it still require two clics.

The MapsService used is the one you provide.

Canadadry commented Oct 27, 2017

My map is supposed to center on the address.
So I have mapped the clickSearchAddress() on a button and It only moves the map on the second click. On the first click I only have the log : Geocoding completed!
Stranger thing, I have put the clickSearchAddress() call on the subscribe of route.paramMapin ngOnInit and there the function work on the first call.

I have tried waiting before starting to click to be sure google map script are loaded but it still require two clics.

The MapsService used is the one you provide.

@FabioBentoLuiz

This comment has been minimized.

Show comment
Hide comment
@FabioBentoLuiz

FabioBentoLuiz Oct 28, 2017

Try it using NgZone as described here

import { NgZone } from '@angular/core';

Add to your constructor

constructor(private _zone: NgZone){
}

Then set lat and lng like this:

this.maps.getGeocoding(address)
            .subscribe(
            result => {
                    this._zone.run(() => {
                    this.lat = result.lat();
                    this.lng = result.lng();
            });
                    
            },
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );

Here is another thread that explain the reason of it.

Let me know if it works.

FabioBentoLuiz commented Oct 28, 2017

Try it using NgZone as described here

import { NgZone } from '@angular/core';

Add to your constructor

constructor(private _zone: NgZone){
}

Then set lat and lng like this:

this.maps.getGeocoding(address)
            .subscribe(
            result => {
                    this._zone.run(() => {
                    this.lat = result.lat();
                    this.lng = result.lng();
            });
                    
            },
            error => console.log(error),
            () => console.log('Geocoding completed!')
            );

Here is another thread that explain the reason of it.

Let me know if it works.

@Canadadry

This comment has been minimized.

Show comment
Hide comment
@Canadadry

Canadadry Oct 31, 2017

It seems to work, but I don't see why.
Thanks

Canadadry commented Oct 31, 2017

It seems to work, but I don't see why.
Thanks

@taneljoeaar

This comment has been minimized.

Show comment
Hide comment
@taneljoeaar

taneljoeaar Nov 11, 2017

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!

taneljoeaar commented Nov 11, 2017

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!

@beachjf

This comment has been minimized.

Show comment
Hide comment
@beachjf

beachjf Nov 26, 2017

@taneljoeaar do you know why I'm getting google is not defined
at MappingService.getLatLan

I mostly copy and paste your code.

Thanks a lot.

beachjf commented Nov 26, 2017

@taneljoeaar do you know why I'm getting google is not defined
at MappingService.getLatLan

I mostly copy and paste your code.

Thanks a lot.

@bookingjini

This comment has been minimized.

Show comment
Hide comment
@bookingjini

bookingjini Dec 6, 2017

@beachjf use the @FabioBentoLuiz solution instead, to get the lat and long because variable " google" may be still undefined as google maps scripts still loading. it works for me.

bookingjini commented Dec 6, 2017

@beachjf use the @FabioBentoLuiz solution instead, to get the lat and long because variable " google" may be still undefined as google maps scripts still loading. it works for me.

@siddheshandhari

This comment has been minimized.

Show comment
Hide comment
@siddheshandhari

siddheshandhari Jan 12, 2018

Try
import { GoogleMapsAPIWrapper } from '@agm/core';
instead of
import { GoogleMapsAPIWrapper } from 'angular2-google-maps/core';
for latest angular

siddheshandhari commented Jan 12, 2018

Try
import { GoogleMapsAPIWrapper } from '@agm/core';
instead of
import { GoogleMapsAPIWrapper } from 'angular2-google-maps/core';
for latest angular

@saiyaff

This comment has been minimized.

Show comment
Hide comment
@saiyaff

saiyaff Jan 22, 2018

@taneljoeaar or try import { } from 'googlemaps'; in whatever the file you're getting the error at.
Make sure the types for googlemaps are installed. (npm install --save @types/googlemaps)

saiyaff commented Jan 22, 2018

@taneljoeaar or try import { } from 'googlemaps'; in whatever the file you're getting the error at.
Make sure the types for googlemaps are installed. (npm install --save @types/googlemaps)

@marcosjoao37

This comment has been minimized.

Show comment
Hide comment
@marcosjoao37

marcosjoao37 Feb 16, 2018

Well I know that is an old question, but I'd like to comment on this topic a code about get the location objects with name and type of the city, state and country. But, in my case, I was needing to get these names from the coordinates of the users. So, to do it I wrote this based on last comments:

import {MapsAPILoader} from '@agm/core';

...

constructor(private mapsAPILoader: MapsAPILoader) {
    // Get this 'res' from some source, like ionic native geolocation
    // Or, for test, create some object like:
    let res = {
        coords: {
            latitude: 40.826514,
            longitude: -73.914628
        }
    }
    this.codeLatLng(res.coords);
  }

...

codeLatLng(coords) {
    this.mapsAPILoader.load().then(() => {
        console.log('google script loaded');
        let latlng = new google.maps.LatLng({lat: coords.latitude, lng: coords.longitude});
        let geocoder = new google.maps.Geocoder();
        let location = {
          country: null,
          state: null,
          city: null
        };
        geocoder.geocode({
          'latLng': latlng
        }, (results, status) => {
          if (status == google.maps.GeocoderStatus.OK) {
            if (results[1]) {
              for (let i = 0; i < results[0].address_components.length; i++) {
                for (let b = 0; b < results[0].address_components[i].types.length; b++) {
                  if (results[0].address_components[i].types[b] == "country") {
                    location.country = !location.country ? results[0].address_components[i] : location.country;
                  } else if (results[0].address_components[i].types[b] == "administrative_area_level_1") {
                    location.state = !location.state ? results[0].address_components[i] : location.state;
                  } else if (results[0].address_components[i].types[b] == "administrative_area_level_2") {
                    location.city = !location.city ? results[0].address_components[i] : location.city;
                  }
                  if (location.city && location.state && location.country) {
                    break;
                  }
                }
              }

              console.log(location);
            } else {
              console.log("Results not available");
            }
          }
          else {
            console.log("Geocoder failed due to: ", status);
          }
        });
      }
    );
  }

To get the coordinates values, I used the ionic native geolocation.
The code came from an angular 2+ & Ionic project.

marcosjoao37 commented Feb 16, 2018

Well I know that is an old question, but I'd like to comment on this topic a code about get the location objects with name and type of the city, state and country. But, in my case, I was needing to get these names from the coordinates of the users. So, to do it I wrote this based on last comments:

import {MapsAPILoader} from '@agm/core';

...

constructor(private mapsAPILoader: MapsAPILoader) {
    // Get this 'res' from some source, like ionic native geolocation
    // Or, for test, create some object like:
    let res = {
        coords: {
            latitude: 40.826514,
            longitude: -73.914628
        }
    }
    this.codeLatLng(res.coords);
  }

...

codeLatLng(coords) {
    this.mapsAPILoader.load().then(() => {
        console.log('google script loaded');
        let latlng = new google.maps.LatLng({lat: coords.latitude, lng: coords.longitude});
        let geocoder = new google.maps.Geocoder();
        let location = {
          country: null,
          state: null,
          city: null
        };
        geocoder.geocode({
          'latLng': latlng
        }, (results, status) => {
          if (status == google.maps.GeocoderStatus.OK) {
            if (results[1]) {
              for (let i = 0; i < results[0].address_components.length; i++) {
                for (let b = 0; b < results[0].address_components[i].types.length; b++) {
                  if (results[0].address_components[i].types[b] == "country") {
                    location.country = !location.country ? results[0].address_components[i] : location.country;
                  } else if (results[0].address_components[i].types[b] == "administrative_area_level_1") {
                    location.state = !location.state ? results[0].address_components[i] : location.state;
                  } else if (results[0].address_components[i].types[b] == "administrative_area_level_2") {
                    location.city = !location.city ? results[0].address_components[i] : location.city;
                  }
                  if (location.city && location.state && location.country) {
                    break;
                  }
                }
              }

              console.log(location);
            } else {
              console.log("Results not available");
            }
          }
          else {
            console.log("Geocoder failed due to: ", status);
          }
        });
      }
    );
  }

To get the coordinates values, I used the ionic native geolocation.
The code came from an angular 2+ & Ionic project.

@ronaldrenteria

This comment has been minimized.

Show comment
Hide comment
@ronaldrenteria

ronaldrenteria Feb 21, 2018

I have implemented the code as you show it but I am getting the following error:

ERROR Error: StaticInjectorError [MapsAPILoader]:
   StaticInjectorError [MapsAPILoader]:
     NullInjectorError: No provider for MapsAPILoader!
     at _NullInjector.get (core.js: 923)
     at resolveToken (core.js: 1211)
     at tryResolveToken (core.js: 1153)
     at StaticInjector.get (core.js: 1024)
     at resolveToken (core.js: 1211)
     at tryResolveToken (core.js: 1153)
     at StaticInjector.get (core.js: 1024)
     at resolveNgModuleDep (core.js: 10586)
     at _createClass (core.js: 10625)
     at _createProviderInstance $ 1 (core.js: 10597)

NOTE: I am using Angular 5

Can you please give me a hand.
Thank you.

ronaldrenteria commented Feb 21, 2018

I have implemented the code as you show it but I am getting the following error:

ERROR Error: StaticInjectorError [MapsAPILoader]:
   StaticInjectorError [MapsAPILoader]:
     NullInjectorError: No provider for MapsAPILoader!
     at _NullInjector.get (core.js: 923)
     at resolveToken (core.js: 1211)
     at tryResolveToken (core.js: 1153)
     at StaticInjector.get (core.js: 1024)
     at resolveToken (core.js: 1211)
     at tryResolveToken (core.js: 1153)
     at StaticInjector.get (core.js: 1024)
     at resolveNgModuleDep (core.js: 10586)
     at _createClass (core.js: 10625)
     at _createProviderInstance $ 1 (core.js: 10597)

NOTE: I am using Angular 5

Can you please give me a hand.
Thank you.

@marcosjoao37

This comment has been minimized.

Show comment
Hide comment
@marcosjoao37

marcosjoao37 Feb 21, 2018

@ronaldrenteria Did you placed

AgmCoreModule.forRoot({
      apiKey: '<YOUR-GOOGLE-API-KEY>'
    })

on your "imports" in app.modules.ts?
Are you using LazyLoading?
That error sometimes occurs when you forget to do some import or to do all of the requirements needed by the lib to work.
You can get more info on that page: Angular Maps - Getting Started.

marcosjoao37 commented Feb 21, 2018

@ronaldrenteria Did you placed

AgmCoreModule.forRoot({
      apiKey: '<YOUR-GOOGLE-API-KEY>'
    })

on your "imports" in app.modules.ts?
Are you using LazyLoading?
That error sometimes occurs when you forget to do some import or to do all of the requirements needed by the lib to work.
You can get more info on that page: Angular Maps - Getting Started.

@ronaldrenteria

This comment has been minimized.

Show comment
Hide comment
@ronaldrenteria

ronaldrenteria Feb 22, 2018

Well I want to tell you, I already show the map and a marker, but what I want to do is convert some directions to latitude and longitude, but this has not been possible.

I do not have the import in the app.modules.ts, because each component is using its own module and if I'm using LazyLoading.

In this case I have a component called home.component.ts and this in turn has its own module called home.module.ts

Before using MapsAPILoader it already showed the map and the markers (example by placing the longitude and latitude manually), but now I want to read the addresses from the DB and get the longitude latitude.

Thank you.

maps.service.ts

import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

// Manejo de Mapas
import { GoogleMapsAPIWrapper, MapsAPILoader } from '@agm/core';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';

declare var google: any;

@Injectable()
export class MapsService 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();
        }
      });
    });
  }
}

home.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { homeRouting } from './home.routing';
import { SmartadminModule} from '../shared/smartadmin.module';
import { HomeComponent} from './home.component';
// 614iT
import { config_church } from './../shared/churchpro.config';
// Indispensable para manejar los mapas.
import { AgmCoreModule, MapsAPILoader } from '@agm/core';
@NgModule({
  imports: [
    CommonModule,
    homeRouting,
    SmartadminModule,
    AgmCoreModule.forRoot({
      apiKey: config_church.GOOGLE_API_KEY
    })
  ],
  declarations: [HomeComponent]
})
export class HomeModule {}

home.component.ts

import { Component, OnInit, NgZone } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';
// Mapas 
import { MapsService } from '../shared/services/maps.service';
@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: []
})
export class HomeComponent implements OnInit {
  title: string = 'My first AGM project';
  lat: number = 4.6517056;
  lng: number = -74.1028404;
  zoom: number = 13;
  Glat: number;
  Glng: number;

  constructor(private _mapsService: MapsService, private __zone: NgZone) {}

  ngOnInit() {}

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

ronaldrenteria commented Feb 22, 2018

Well I want to tell you, I already show the map and a marker, but what I want to do is convert some directions to latitude and longitude, but this has not been possible.

I do not have the import in the app.modules.ts, because each component is using its own module and if I'm using LazyLoading.

In this case I have a component called home.component.ts and this in turn has its own module called home.module.ts

Before using MapsAPILoader it already showed the map and the markers (example by placing the longitude and latitude manually), but now I want to read the addresses from the DB and get the longitude latitude.

Thank you.

maps.service.ts

import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

// Manejo de Mapas
import { GoogleMapsAPIWrapper, MapsAPILoader } from '@agm/core';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';

declare var google: any;

@Injectable()
export class MapsService 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();
        }
      });
    });
  }
}

home.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { homeRouting } from './home.routing';
import { SmartadminModule} from '../shared/smartadmin.module';
import { HomeComponent} from './home.component';
// 614iT
import { config_church } from './../shared/churchpro.config';
// Indispensable para manejar los mapas.
import { AgmCoreModule, MapsAPILoader } from '@agm/core';
@NgModule({
  imports: [
    CommonModule,
    homeRouting,
    SmartadminModule,
    AgmCoreModule.forRoot({
      apiKey: config_church.GOOGLE_API_KEY
    })
  ],
  declarations: [HomeComponent]
})
export class HomeModule {}

home.component.ts

import { Component, OnInit, NgZone } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';
// Mapas 
import { MapsService } from '../shared/services/maps.service';
@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: []
})
export class HomeComponent implements OnInit {
  title: string = 'My first AGM project';
  lat: number = 4.6517056;
  lng: number = -74.1028404;
  zoom: number = 13;
  Glat: number;
  Glng: number;

  constructor(private _mapsService: MapsService, private __zone: NgZone) {}

  ngOnInit() {}

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

This comment has been minimized.

Show comment
Hide comment
@ramossantiago

ramossantiago Feb 23, 2018

Hi everybody

Maybe someone is facing a similar problem.

I need to customize the AGM library, i downloaded the code and included this code like a part of my project, therefore i add the agmCoreModule from local src folder in apps.module, like this.

import { AgmCoreModule } from '../agmLocalModule/core.module';

AgmCoreModule.forRoot({
apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}),

i have a page with markers generated in a ngFor loop. But i am having the next error.

```

<agm-marker *ngFor="let ubicacion of ubicaciones"
[latitude]="ubicacion.posicion.latitud"
[longitude]="ubicacion.posicion.longitud"
[markerClickable]="true"
>


ERROR Error: Uncaught (in promise): ReferenceError: google is not defined
ReferenceError: google is not defined
    at MarkerManager.webpackJsonp.102.MarkerManager.addMarker (marker-manager.ts:82)
    at AgmMarker.webpackJsonp.291.AgmMarker.ngOnChanges (marker.ts:169)


Any idea what could be the problem

ramossantiago commented Feb 23, 2018

Hi everybody

Maybe someone is facing a similar problem.

I need to customize the AGM library, i downloaded the code and included this code like a part of my project, therefore i add the agmCoreModule from local src folder in apps.module, like this.

import { AgmCoreModule } from '../agmLocalModule/core.module';

AgmCoreModule.forRoot({
apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}),

i have a page with markers generated in a ngFor loop. But i am having the next error.

```

<agm-marker *ngFor="let ubicacion of ubicaciones"
[latitude]="ubicacion.posicion.latitud"
[longitude]="ubicacion.posicion.longitud"
[markerClickable]="true"
>


ERROR Error: Uncaught (in promise): ReferenceError: google is not defined
ReferenceError: google is not defined
    at MarkerManager.webpackJsonp.102.MarkerManager.addMarker (marker-manager.ts:82)
    at AgmMarker.webpackJsonp.291.AgmMarker.ngOnChanges (marker.ts:169)


Any idea what could be the problem
@SainiSK

This comment has been minimized.

Show comment
Hide comment
@SainiSK

SainiSK Mar 7, 2018

For all those who are getting 'google is undefined' error:

use this event 'mapReady' of agm-map element.
"https://angular-maps.com/api-docs/agm-core/components/AgmMap.html#mapReady"

SainiSK commented Mar 7, 2018

For all those who are getting 'google is undefined' error:

use this event 'mapReady' of agm-map element.
"https://angular-maps.com/api-docs/agm-core/components/AgmMap.html#mapReady"

@mathias-ewald

This comment has been minimized.

Show comment
Hide comment
@mathias-ewald

mathias-ewald Mar 14, 2018

Could someone come up with a working example?

mathias-ewald commented Mar 14, 2018

Could someone come up with a working example?

@supruniuk

This comment has been minimized.

Show comment
Hide comment
@supruniuk

supruniuk Apr 10, 2018

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

supruniuk commented Apr 10, 2018

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

@maksimbykov

This comment has been minimized.

Show comment
Hide comment
@maksimbykov

maksimbykov May 4, 2018

Can I call mapsAPILoader.load() multiple times?

maksimbykov commented May 4, 2018

Can I call mapsAPILoader.load() multiple times?

@henoktsegaye

This comment has been minimized.

Show comment
Hide comment
@henoktsegaye

henoktsegaye May 22, 2018

hi every body i had a little problem , am new to AGM and angular too , but the thing is i got the place_id , i wanted to change this to latlng object thats was it , any help is appriciated

henoktsegaye commented May 22, 2018

hi every body i had a little problem , am new to AGM and angular too , but the thing is i got the place_id , i wanted to change this to latlng object thats was it , any help is appriciated

@maksimbykov

This comment has been minimized.

Show comment
Hide comment
@maksimbykov

maksimbykov May 22, 2018

@henoktsegaye basic principle here https://developers.google.com/maps/documentation/javascript/examples/geocoding-place-id
so you can use example from posted above, in a few words you need this.geocoder = new google.maps.Geocoder() and geocoder.geocode({'placeId': placeId}, callbackFunction(results, status)) but this will be after the script loaded

maksimbykov commented May 22, 2018

@henoktsegaye basic principle here https://developers.google.com/maps/documentation/javascript/examples/geocoding-place-id
so you can use example from posted above, in a few words you need this.geocoder = new google.maps.Geocoder() and geocoder.geocode({'placeId': placeId}, callbackFunction(results, status)) but this will be after the script loaded

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment