-
-
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 }) | |
]; |
Hi..is this working in Angular 2? I am always getting 'Unable to determine your location' in Chrome.
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?
Thank you. Can this code be modified for use is Angular 4?
@ravivit9 you probably need to to delete the: observer.complete();
`
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 }
];
`
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";
}
}
}
Thank you! I use rx-dom library for this. I think it can be more convenient.
Hi @andreypelykh, did you update this with rx-dom? if yes please share.
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');
});
This library solved the problem and works with Angular 11: https://www.npmjs.com/package/@ng-web-apis/geolocation
Thanks