Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import {Injectable, provide} from 'angular2/core';
import {Observable} from 'rxjs';
const GEOLOCATION_ERRORS = {
'errors.location.unsupportedBrowser': 'Browser does not support location services',
'errors.location.permissionDenied': 'You have rejected access to your location',
'errors.location.positionUnavailable': 'Unable to determine your location',
'errors.location.timeout': 'Service timeout has been reached'
};
@Injectable()
export class GeolocationService {
/**
* Obtains the geographic position, in terms of latitude and longitude coordinates, of the device.
* @param {Object} [opts] An object literal to specify one or more of the following attributes and desired values:
* - enableHighAccuracy: Specify true to obtain the most accurate position possible, or false to optimize in favor of performance and power consumption.
* - timeout: An Integer value that indicates the time, in milliseconds, allowed for obtaining the position.
* If timeout is Infinity, (the default value) the location request will not time out.
* If timeout is zero (0) or negative, the results depend on the behavior of the location provider.
* - maximumAge: An Integer value indicating the maximum age, in milliseconds, of cached position information.
* If maximumAge is non-zero, and a cached position that is no older than maximumAge is available, the cached position is used instead of obtaining an updated location.
* If maximumAge is zero (0), watchPosition always tries to obtain an updated position, even if a cached position is already available.
* If maximumAge is Infinity, any cached position is used, regardless of its age, and watchPosition only tries to obtain an updated position if no cached position data exists.
* @returns {Observable} An observable sequence with the geographical location of the device running the client.
*/
public getLocation(opts): Observable<any> {
return Observable.create(observer => {
if (window.navigator && window.navigator.geolocation) {
window.navigator.geolocation.getCurrentPosition(
(position) => {
observer.next(position);
observer.complete();
},
(error) => {
switch (error.code) {
case 1:
observer.error(GEOLOCATION_ERRORS['errors.location.permissionDenied']);
break;
case 2:
observer.error(GEOLOCATION_ERRORS['errors.location.positionUnavailable']);
break;
case 3:
observer.error(GEOLOCATION_ERRORS['errors.location.timeout']);
break;
}
},
opts);
}
else {
observer.error(GEOLOCATION_ERRORS['errors.location.unsupportedBrowser']);
}
});
}
}
export var geolocationServiceInjectables: Array<any> = [
provide(GeolocationService, { useClass: GeolocationService })
];
@mikepc

This comment has been minimized.

Copy link

mikepc commented Apr 7, 2016

Can watchPosition be substituted for getCurrentPosition and have the observer be automatically updated?

@raviteja-avvari

This comment has been minimized.

Copy link

raviteja-avvari commented Apr 21, 2016

Where do I get the coordinates saved? I am not able to retrieve them

@SpazzMarticus

This comment has been minimized.

Copy link

SpazzMarticus commented Jun 30, 2016

@mikepc You probably already found it out yourself: Yes you can substitute watchPosition for getCurrentPosition

@raviteja-avvari You have to subscribe to the observable returned by getLocation

this.instanceOfService.getLocation().subscribe(
    function(position) { ... },
    function(error) { ... },
    function(complete) { ... }
);
@FunnyGhost

This comment has been minimized.

Copy link

FunnyGhost commented Dec 4, 2016

Thanks for this! I have a question, though. I have a method that gets data from a server based on the location and it returns an Observable.
Like this:

    getMessages(): Observable<IMessage[]> {
        return this._http.get(this.someUrl)
            .map((response: Response) => <IMessage[]>response.json())
            .do(data => console.log('All: ' + JSON.stringify(data)))
            .catch(this.handleError);
    }

The someUrl must contain the coordinates as well, so how can I make sure that the coordinates are gotten before calling the http and returning the result?

Thanks!

@photostu

This comment has been minimized.

Copy link

photostu commented Dec 16, 2016

Thank you for this!
This code can be updated now to not use provide :)

@DarkChopper

This comment has been minimized.

Copy link

DarkChopper commented Jan 19, 2017

Thanks

@Rchua72

This comment has been minimized.

Copy link

Rchua72 commented Jun 17, 2017

Hi..is this working in Angular 2? I am always getting 'Unable to determine your location' in Chrome.

@ravivit9

This comment has been minimized.

Copy link

ravivit9 commented Aug 2, 2017

Hi, I am able to get the location first, I am using watchPosition instead of getCurrentPosition. But I am getting the position only once and it's not watching anymore. Any thoughts here?

@suraj021

This comment has been minimized.

Copy link

suraj021 commented Aug 9, 2017

Thank you. Can this code be modified for use is Angular 4?

@gise88

This comment has been minimized.

Copy link

gise88 commented Sep 1, 2017

@ravivit9 you probably need to to delete the: observer.complete();

@jagdishmastek

This comment has been minimized.

Copy link

jagdishmastek commented Dec 6, 2017

`
Angular 5 Geolocation service

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

const GEOLOCATION_ERRORS = {
'errors.location.unsupportedBrowser': 'Browser does not support location services',
'errors.location.permissionDenied': 'You have rejected access to your location',
'errors.location.positionUnavailable': 'Unable to determine your location',
'errors.location.timeout': 'Service timeout has been reached'
};

@Injectable()
export class GeoLocationService {

public getLocation(geoLocationOptions?: any): Observable {
geoLocationOptions = geoLocationOptions || { timeout: 5000 };

    return Observable.create(observer => {

      if (window.navigator && window.navigator.geolocation) {
        window.navigator.geolocation.getCurrentPosition(
          (position) => {
            observer.next(position);
            observer.complete();
          },
          (error) => {
            switch (error.code) {
              case 1:
                observer.error(GEOLOCATION_ERRORS['errors.location.permissionDenied']);
                break;
              case 2:
                observer.error(GEOLOCATION_ERRORS['errors.location.positionUnavailable']);
                break;
              case 3:
                observer.error(GEOLOCATION_ERRORS['errors.location.timeout']);
                break;
            }
          },
          geoLocationOptions);
    } else {
          observer.error(GEOLOCATION_ERRORS['errors.location.unsupportedBrowser']);
    }

    });



  }
}

export let geolocationServiceInjectables: Array<any> = [
  {provide: GeoLocationService, useClass: GeoLocationService }
];

`

@HarelM

This comment has been minimized.

Copy link

HarelM commented Jan 26, 2018

A different but similar approach if anyone is interested - this one is based on publishing events when the service is enabled:
Written with angular 5.
I'm not very strong with observables so the code might be shorter.

import { Injectable, EventEmitter } from "@angular/core";

declare type GeoLocationServiceState = "disabled" | "searching" | "tracking";

@Injectable()
export class GeoLocationService {

    private state: GeoLocationServiceState;
    private watchNumber: number;

    public positionChanged: EventEmitter<Position>;

    constructor() {
        this.watchNumber = -1;
        this.positionChanged = new EventEmitter();
        this.state = "disabled";
    }

    public getState(): GeoLocationServiceState {
        return this.state;
    }

    public enable() {
        switch (this.state) {
            case "disabled":
                this.startWatching();
                return;
            case "searching":
            case "tracking":
                return;

        }
    }
    public disable() {
        switch (this.state) {
        case "disabled":
            return;
        case "searching":
        case "tracking":
            this.stopWatching();
            return;
        }
    }

    private startWatching() {
        if (window.navigator && window.navigator.geolocation) {
            this.state = "searching";
            this.watchNumber = window.navigator.geolocation.watchPosition(
                (position) => {
                    this.state = "tracking";
                    this.positionChanged.next(position);
                },
                (error) => {
                    // sending error will terminate the stream
                    this.positionChanged.next(null);
                    this.disable();
                },
                {
                    enableHighAccuracy: true,
                    timeout: 5000
                });
        }
    }

    private stopWatching() {
        if (this.watchNumber !== -1) {
            window.navigator.geolocation.clearWatch(this.watchNumber);
            this.watchNumber = -1;
            this.state = "disabled";
        }
    }
}
@andreypelykh

This comment has been minimized.

Copy link

andreypelykh commented Feb 16, 2018

Thank you! I use rx-dom library for this. I think it can be more convenient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.