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
Copy link
Copy Markdown

mikepc commented Apr 7, 2016

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

Copy link
Copy Markdown

ghost commented Apr 21, 2016

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!

@photostu
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
Copy link
Copy Markdown

Rchua72 commented Jun 17, 2017

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

@ravivit9
Copy link
Copy Markdown

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
Copy link
Copy Markdown

suraj021 commented Aug 9, 2017

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

@gise88
Copy link
Copy Markdown

gise88 commented Sep 1, 2017

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

@jagdishmastek
Copy link
Copy Markdown

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
Copy link
Copy Markdown

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
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
Copy link
Copy Markdown

askuri commented Apr 13, 2021

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