我有监控设备位置的服务:
getLocation(opts): Observable<any> {
return Observable.create(observer => {
if (window.navigator && window.navigator.geolocation) {
window.navigator.geolocation.watchPosition((position) => {
observer.next(position);
}, (error) => {
switch (error.code) {
case 1:
observer.error('errors.location.permissionDenied');
break;
case 2:
observer.error('errors.location.positionUnavailable');
break;
case 3:
observer.error('errors.location.timeout');
break;
}
}, opts);
} else {
observer.error('errors.location.unsupportedBrowser');
}
});
}
然后检索lat,long in component:
ngOnInit() {
var source = this.locationService.getLocation({enableHighAccuracy:true, maximumAge:30000, timeout:27000});
source.subscribe(pos => {
this.lat = pos.coords.latitude;
this.long = pos.coords.longitude;
}, err => {
this.err = err;
console.log(err);
});
}
此代码在macbook和iphone上的浏览器中正常工作,即它可以在设备移动时检索和更新位置。
但是在我的ipad上(wifi只有没有gps)它可以在第一时间获得位置,然后几秒钟后,服务返回错误代码2,即位置不可用和浏览器停止更新位置。我不确定它是否停止工作或它仍然在运行,但总是返回错误代码2。
我的问题是:
答案 0 :(得分:0)
我在某些浏览器中使用navigator.geolocation.watchPosition在使用RxJS,Meteor和其他一些东西的Angular2服务中遇到了一个奇怪的错误。不确定原因是什么,但是在第一次回调之后“this”超出了范围,并且在将来的回调中无法解决。修复是为当前类创建一个本地范围的引用:
startTracking() {
let that = this; //The fix
let opts = {maximumAge: 60000, timeout: 30000}
this.watchId = navigator.geolocation.watchPosition((position) =>
{
console.log(position);
that.locationTrackingActive = true;
that.reactiveDeviceLocation.next(position.coords);
},
(err) =>
{
console.log(err);
that.locationTrackingActive = false;
},
opts);
}
您不需要在发生错误后重新订阅watchPosition,它会继续尝试,直到它能够获得信号。对于您的observable,使用BehaviorSubject(上面的reactiveDeviceLocation)允许您设置默认的起始位置,然后仅在成功时更新它...这样当新客户端订阅时,它们将被赋予默认(或最新)位置并且可以可以使用它,直到watchPosition成功更新主题。
我按如下方式设置(在同一服务中)
reactiveDeviceLocation: Rx.BehaviorSubject<Object> = new Rx.BehaviorSubject<Object>({latitude:37.5, longitude:122});
getReactiveDeviceLocation() {
return this.reactiveDeviceLocation;
}
然后,该服务的任何消费者都可以致电
MyService.getReactiveDeviceLocation.subscribe((pos) => {
console.log(pos); //Last known location.
})
答案 1 :(得分:0)
在这里,我正在使用watchPosition
函数从用户那里获取位置信息。创建具有默认位置的主题(可选)。加载组件后,调用getLocation
,并在组件内使用异步管道显示数据。
<div *ngIf="coordindates | async">
<p>
{{coordindates | async | json}}
</p>
</div>
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import {
LocationService
} from '@app/core';
import { Observable } from 'rxjs';
@Component({
selector: 'app-location',
templateUrl: './location.component.html',
styleUrls: ['./location.component.scss']
})
export class LocationComponent implements OnInit {
coordindates: Observable<Object>;
constructor(private locationService: LocationService) { }
ngOnInit(): void {
this.coordindates = this.locationService.getLocation();
}
}
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class LocationService {
public watchId: number;
public locationTrackingActive = false;
public currentLoation: { latitude: number, longitude: number } = { latitude: undefined, longitude: undefined };
private reactiveDeviceLocation$: Subject<Object>;
constructor() {
this.reactiveDeviceLocation$ = new BehaviorSubject<Object>(this.currentLoation);
}
getLocation(): Observable<Object> {
const opts = { enableHighAccuracy: true, maximumAge: 60000, timeout: 30000 };
this.watchId = navigator.geolocation.watchPosition((position) => {
this.locationTrackingActive = true;
this.currentLoation = { latitude: position.coords.latitude, longitude: position.coords.longitude };
this.reactiveDeviceLocation$.next(this.currentLoation);
},
(err) => {
console.log(err);
this.locationTrackingActive = false;
},
opts);
return this.reactiveDeviceLocation$;
}
}