Navigator.permissions.query: Geolocation onChange not working in Firefox
Asked Answered
E

1

11

I am trying to use the Permissions API: https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query Which should be supported by Firefox. (I am currently using Firefox Developer Edition 66.0b14).

I have a page where I initially check user permissions. Something like;

if (navigator.permissions) {
  navigator.permissions.query({ name: 'geolocation' }).then(result => {
    if (result.state === 'granted') {
      this.getCurrentPosition()
    } else if (result.state === 'prompt') {
      this.getCurrentPosition()
      console.log('Permissions requested. Waiting for user input...')
    } else if (result.state === 'denied') {
      this.locationError = true
    }
    result.onchange = event => {
      if (event.target.state === 'granted') {
        this.locationError = false
        this.getCurrentPosition()
        console.log('Thanks for letting us know...')
      } else if (event.target.state === 'denied') {
        this.locationError = true
      }
    }
  })
}

Now this works all fine in Chrome for example. (Btw: I use this.locationError to show some info window saying that the app will only work with location services enabled)

Anyway, if I open it in Firefox I get the prompt as expected: Now If I check the box «Remember this decision» and send either Allow/Block, I see that the onchange is executed as expected, giving me the possibility to react onto the users decision.

BUT, if I don't check this box, and just deny or allow once, the onchange is not called, leaving me in the unknown of what actually happened. Also this the state remains being 'prompt'.

I also tried to set an interval to check Permissions again after some time, but again it would just open the prompt asking for the permission. The state never updates or changes from 'prompt' to 'denied' or 'granted'.

Is there something I am missing, or is this a Firefox bug.

Thanks for any hints

Cheers

Exergue answered 12/3, 2019 at 17:5 Comment(4)
I'm running into this as well. Seems kinda weird, because if you deny and you don't check the remember box, even though the permissionstatus.state still says prompt, the fact that the user denied it seems to be remembered. This seems WAY opposite of intuitive: if there is a checkbox for remembering an end-users choice, and that end-user doesn't check that box, the fact that that choice is REMEMBERED just doesn't make sense...Eaten
@JakeSmith but it should be remembered for that session atleast right?Yulan
I don't see why that is an assumption I should make. But I have no clue. If a user doesn't say remember, then remember it should not would be my assumption. The app shouldn't incessantly ask the user for permission, but I don't see how the user is able to change their mind if the app isn't allowed to ask for permission again.Eaten
For anyone having the same issue, it's a bug in Firefox: bugzilla.mozilla.org/show_bug.cgi?id=1754372Relegate
D
2

I was unable to get the onchange function or change event to work for Firefox but was able to find a workaround that worked just as well to identify a change in permission:

Note: this fix will only work if you are using geolocation.getCurrentPosition

  navigator.permissions.query({
    name: 'geolocation'
  }).then(function(result) {
      
    const onLocationFetchSuccess = (position) => {
      /*
         Consume location coordinates here and proceed as required
         using position.coords.latitude and position.coords.longitude
      */
    };

    const onLocationFetchFailure = (error = {}) => {
      // Error code 1 corresponds to user denying/blocking the location permission
      if (error.code === 1) {
        // Respond to failure case as required
      }
    };

    navigator.geolocation.getCurrentPosition(onLocationFetchSuccess, onLocationFetchFailure);

    if (result.state === 'denied') {
      onLocationFetchFailure();
    }

    // This will still work for Chrome
    result.onchange = function() {
      if (result.state === 'denied') {
        onLocationFetchFailure();
      }
    }
  })

This solution will trigger the failure case twice for Chrome browsers. To avoid that one can check for current browser to conditionally prevent sending the onLocationFetchFalure callback to getCurrentPosition for Chrome browsers.

TLDR; the fix here is that instead of relying on the change event / onchange function to be triggered, we pass an error callback to getCurrentPosition which is triggered when the location permission is changed through the permission dialog. This error callback provides an error code of 1 when the user denies/blocks the location permission.

Dyewood answered 24/6, 2021 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.