The navigator.geolocation.watchPosition call did not return any available position information

I offer a service that monitors the position of devices:

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');
        }
    });
}

then retrieve latitude and longitude in the 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);
    });
}

This code works well on browsers on MacBook and iPhone, allowing for position updates when the device moves.

However, on my iPad (which is Wi-Fi only and lacks GPS), it retrieves the position initially but after a few seconds, the service returns error code 2 indicating position unavailability, and the browser stops updating the position. I'm unsure if it has stopped working or continues to run but constantly returns error code 2.

My queries are:

  1. Does watchPosition require GPS to function? My MacBook also lacks GPS.
  2. If an error occurs and is returned from the observable, do I need to resubscribe to obtain data (position) again, or should I simply wait until the error resolves itself?

Answer №1

Utilizing the watchPosition function, I am able to obtain location data from the user. You can create a subject with an optional default location. Upon loading the component, simply call the getLocation method and utilize an async pipe within your component to display the retrieved data.

Check out the Live Demo here!

location.component.html

<div *ngIf="coordinates | async">
  <p>
    {{coordinates | async | json}}
  </p>
</div>

location.component.ts

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 {
    coordinates: Observable<Object>;
    constructor(private locationService: LocationService) { }

    ngOnInit(): void {
        this.coordinates = this.locationService.getLocation();
    }
}

location.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
@Injectable({
    providedIn: 'root'
})
export class LocationService {
    public watchId: number;
    public locationTrackingActive = false;
    public currentLocation: { latitude: number, longitude: number } = { latitude: undefined, longitude: undefined };
    private reactiveDeviceLocation$: Subject<Object>;

    constructor() {
        this.reactiveDeviceLocation$ = new BehaviorSubject<Object>(this.currentLocation);
    }

    getLocation(): Observable<Object> {
        const options = { enableHighAccuracy: true, maximumAge: 60000, timeout: 30000 };
        this.watchId = navigator.geolocation.watchPosition((position) => {
            this.locationTrackingActive = true;
            this.currentLocation = { latitude: position.coords.latitude, longitude: position.coords.longitude };
            this.reactiveDeviceLocation$.next(this.currentLocation);
        },
        (err) => {
            console.log(err);
            this.locationTrackingActive = false;
        },
        options);
        return this.reactiveDeviceLocation$;
    }
}

Answer №2

Encountering a peculiar bug while using navigator.geolocation.watchPosition in an Angular2 service with RxJS, Meteor, and various other components on specific browsers. The issue seems to be related to "this" going out of scope after the initial callback, rendering it inaccessible in subsequent callbacks. To resolve this, a locally scoped reference to the current class needs to be created:

startTracking() {
    let that = this; //The solution            
    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);

}

No need to resubscribe to watchPosition post-error as it will keep attempting until a signal is received. By utilizing a BehaviorSubject for your observable (as seen in reactiveDeviceLocation above), you can establish a default starting location and only update it upon success. This approach ensures that new clients subscribing will receive the default or most recent location and can then work with that information until watchPosition successfully updates the subject.

The setup within the same service looks like this:

reactiveDeviceLocation: Rx.BehaviorSubject<Object> = new Rx.BehaviorSubject<Object>({latitude:37.5, longitude:122});

getReactiveDeviceLocation() {
    return this.reactiveDeviceLocation;
}

Subsequently, any service consumer can call:

MyService.getReactiveDeviceLocation.subscribe((pos) => {
   console.log(pos); //Last known location.
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error with Typescript types when using Styled Components

After successfully setting up styled-components in react-native, I encountered an issue while trying to use it in a simple example with react-native-web: import * as React from 'react'; import styled from 'styled-components'; export d ...

Ensuring Valid Numbers in Angular 2

Working with Angular 2 (2.0.0) and TypeScript to set validation rules within an <input> element in a table column. For instance, let's say we have a table and some input fields: <table> <tr> <td>Values: {{ dataFromSer ...

Exploring the concepts of type intersection in TypeScript

I attempted to create a type definition for recurrent intersection, in order to achieve this specific behavior: type merged = Merged<[{a: string}, {b: string}, ...]> to end up with {a: string} & {b: string} & ... I came up with some type u ...

Can NODE_PATH be configured in Typescript?

Before, I worked on my React app with ES6 and used NODE_PATH='src' to import files starting from the src folder. However, since switching to Typescript, I've realized that NODE_PATH is not supported. After some investigation, I discovered th ...

I'm having difficulty updating the Angular CLI version

I am currently running Angular CLI version 7.1.4 and I have been attempting to update to the latest version. However, each time I try to update, I encounter a multitude of errors. I have attempted using the command ng update @angular/core @angular/cli b ...

Issue with rendering HTML tags when replacing strings within Ionic 2 and Angular 2

I am currently working with an array of content in my JSON that includes URLs as plain text. My goal is to detect these text URLs and convert them into actual clickable links. However, I'm facing an issue where even though the URL is properly replaced ...

Utilizing variables for Protractor command line parameters

I am struggling to make variables work when passing parameters as a string in my code. Conf.ts params: { testEnvironment: TestEnvironment.Prod, }, env.ts export enum TestEnvironment { Dev = 'dev', QA = 'qa', Prod ...

Having trouble resolving all parameters for 'Router' in Angular 2 testing with Router

Currently, I am in the process of testing a component that has Router injected in the constructor (TypeScript): constructor( private _router: Router, private dispatcher: Observer<Action>, fb: FormBuilder ) { ... } Here are the test cases ...

Discover the perfect way to implement true lazyloading using NativeScript Angular tabs and BottomNavigation

Currently working on an app using nativescipt, I've successfully added BottomNavigation with lazy loading and Tab components in child pages. The code structure resembles the following: export const routes: Routes = [ { path: '', red ...

Obtaining Data from a Database Using Angular

I have developed a front-end website using Angular as my framework, integrated with node.js. To interact with the database, I created a "server.ts" file and connected it successfully to my DB. Now, my goal is to fetch data from the database and display i ...

Generate a byte array in JavaScript

How can a byte array be created from a file in JavaScript (or Typescript) to send to a C# WebApi service and be consumable by the C# byte array method parameter? Could you provide an example of the JavaScript code? The context here is an Angular 4+ applic ...

How to efficiently update a child component in React using UseState and establish a connection back to the parent component

I am currently working on developing a prototype for a master/detail scenario in React and Material-UI. The task involves creating a basic list of objects with the ability to edit and save an item using a dialog. While I have successfully updated the visit ...

Ionic - InAppBrowser continuously redirects to external web browser instead of staying within the in-app browser

When I was testing my Ionic App on localhost:8100 page using ionic serve, the developer console showed a warning message: Native: InAppBrowser is not installed or you are running on a browser. Falling back to window.open. The same issue occurred when I ...

Comparing the Calculation of CSS Selector Specificity: Class versus Elements [archived]

Closed. This question requires additional information for debugging purposes. It is not currently accepting answers. ...

Encountering an issue in Angular 8 with ng2-chart where the error message reads: "RangeError: Maximum call stack size

I encountered an issue with the following error message: ERROR RangeError: Maximum call stack size exceeded at ChartElement.update (Chart.js:11474) at fitBoxes (Chart.js:7127) at fitBoxes (Chart.js:7145) at fitBoxes (Chart.js:7145) at f ...

What is the correct way to specify the data type for the useState hook when I intend to store an array of objects?

My dilemma involves storing an array of objects using the useState hook, but I am struggling with the syntax required to describe the expected type. The type that I want to store is Array<Updates>. Below is the code I have: const [messages, setMessa ...

Attempting to execute a post request followed by a get request

I need assistance optimizing my code. What I am trying to achieve is to create a user (partner) and upon completion of the post request, fetch all partners from an API. This includes the newly created partner so that I can access their ID to use in subsequ ...

Tips on integrating Ionic 2 with Angular 2 services

I'm a beginner with Ionic 2. I came across information in the Angular 2 documentation stating that services need to be injected during application bootstrapping. However, I didn't see any mention of bootstrapping while following the Ionic 2 tuto ...

"Overcoming obstacles in managing the global state of a TypeScript preact app with React/Next signals

Hello, I recently attempted to implement a global app state in Preact following the instructions provided in this documentation. However, I kept encountering errors as this is my first time using useContext and I suspect that my configuration might be inco ...

Checking for valid positive numbers and detecting invalid dates with Angular form techniques

How do I validate an input to ensure it is a positive number and a date no earlier than the current date using Angular's FormControl, FormBuilder, and FormGroup? Here is my code: HTML: <p>Enter price:</p> <input type="number" formCont ...