Skip to content

Initial state of PermissionsController for geolocation doesn't seem to reflect its real state on pageload #32

@TonySpegel

Description

@TonySpegel

Hi there!

I was just about to use the PermissionController to be able to work with the geolocations or to display the UI in a slightly different way depending on the state. I'm not sure if I'm doing something wrong or not, but the initial state doesn't seem to correspond to the actual state. I followed the demo in the docs and added some UI with help from lit/task, both in Chrome and Firefox the initial state after I open the page is “prompt” no matter if the permission was granted or denied.

I've got a reproduction repository (you can just run npm run dev) and also a github page with a demo

gps-permission-2024-07-24_22.29.10.mp4

and also my code inline here:

import { html, LitElement, TemplateResult } from 'lit';
import { customElement, state } from 'lit/decorators.js';

import { PermissionsController } from 'relit';
import { Task } from '@lit/task';
import { choose } from 'lit/directives/choose.js';

type coords = Pick<GeolocationCoordinates, 'latitude' | 'longitude'>;

@customElement('app-permission')
export class AppHome extends LitElement {
  @state()
  latitude: number | undefined = 52.522138048058856;

  @state()
  longitude: number | undefined = 13.394977670545542;

  private _geoPermissionController = new PermissionsController(
    this,
    'geolocation'
  );

  private _getGpsPosition(
    options: PositionOptions = { enableHighAccuracy: true }
  ): Promise<coords> {
    return new Promise((resolve, reject) => {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const { latitude, longitude } = position.coords;
          resolve({ latitude, longitude });
        },
        (error) => reject(error),
        options
      );
    });
  }

  private _gpsPositionTask = new Task(this, {
    task: () => this._getGpsPosition(),
    onComplete: (coords) => {
      this.latitude = coords.latitude;
      this.longitude = coords.longitude;
    },
    autoRun: false,
    args: () => [this.latitude, this.longitude] as const,
  });

  private _permissionPending = () => {
    return html`
      <sl-button
        @click=${() => {
          this._gpsPositionTask.run();
        }}
      >
        Ask for location permission
      </sl-button>
    `;
  };

  private _permissionDenied = () => html`
    <sl-button variant="warning">we got a problem</sl-button>
  `;

  private _permissionGranted = () => html`
    <sl-button @click=${() => this._gpsPositionTask.run()} variant="primary">
      Get GPS Position
    </sl-button>
  `;

  private _gpsButtonTemplate = (state: PermissionState) => html`
    ${choose<PermissionState, TemplateResult>(state, [
      ['prompt', () => this._permissionPending()],
      ['granted', () => this._permissionGranted()],
      ['denied', () => this._permissionDenied()],
    ])}
  `;

  render() {
    return html`
      <h2>Permission works</h2>
      <p>${this._geoPermissionController.state}</p>

      ${'geolocation' in navigator
        ? this._gpsButtonTemplate(this._geoPermissionController.state)
        : null}
    `;
  }
}

btw it doesn't seem to matter where or when the state is obtained.

I'm sorry if I misunderstood or misused something, thanks for the help :) and let me know if I can provide more details!

Edit: added a demo

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions