Skip to content

Instantly share code, notes, and snippets.

@sasha7
Last active February 21, 2022 12:44
Show Gist options
  • Select an option

  • Save sasha7/0c32f3686eb49d44ccc8 to your computer and use it in GitHub Desktop.

Select an option

Save sasha7/0c32f3686eb49d44ccc8 to your computer and use it in GitHub Desktop.
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

mikepc commented Apr 7, 2016

Copy link
Copy Markdown

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

ghost commented Apr 21, 2016

Copy link
Copy Markdown

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

@SpazzMarticus

Copy link
Copy Markdown

@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

Copy link
Copy Markdown

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!

@stusquared

Copy link
Copy Markdown

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

@xtiannyeto

Copy link
Copy Markdown

Thanks

@Rchua72

Rchua72 commented Jun 17, 2017

Copy link
Copy Markdown

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

@ravivit9

ravivit9 commented Aug 2, 2017

Copy link
Copy Markdown

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

suraj021 commented Aug 9, 2017

Copy link
Copy Markdown

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

@gise88

gise88 commented Sep 1, 2017

Copy link
Copy Markdown

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

@jagdishmastek

jagdishmastek commented Dec 6, 2017

Copy link
Copy Markdown

`
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

HarelM commented Jan 26, 2018

Copy link
Copy Markdown

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

Copy link
Copy Markdown

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

@rmxakalogistik

Copy link
Copy Markdown

Hi @andreypelykh, did you update this with rx-dom? if yes please share.

@andreypelykh

Copy link
Copy Markdown

Hello, @rmxakalogistik! What do you mean? You can simply use an example from the link that I provided. https://github.com/Reactive-Extensions/RxJS-DOM/blob/master/doc/operators/watchposition.md#example

var source = Rx.DOM.geolocation.watchPosition();

var subscription = source.subscribe(
  function (pos) {
    console.log('Next:' + position.coords.latitude + ',' + position.coords.longitude);
  },
  function (err) {
    var message = '';
    switch (err.code) {
      case err.PERMISSION_DENIED:
        message = 'Permission denied';
        break;
      case err.POSITION_UNAVAILABLE:
        message = 'Position unavailable';
        break;
      case err.PERMISSION_DENIED_TIMEOUT:
        message = 'Position timeout';
        break;
    }
    console.log('Error: ' + message);
  },
  function () {
    console.log('Completed');
  });

@askuri

askuri commented Apr 13, 2021

Copy link
Copy Markdown

This library solved the problem and works with Angular 11: https://www.npmjs.com/package/@ng-web-apis/geolocation

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