web-dev-qa-db-fra.com

fonction fail jamais appelée si l'utilisateur refuse de partager la géolocalisation dans firefox

J'ai donc ce code javascript. Dans les safari et chrome, si l'utilisateur refuse de partager l'emplacement, il échouera comme il se doit; Cependant, dans Firefox, ce n'est pas le cas. 

Toute aide appréciée. 

function initGeolocation()
{
    if( navigator.geolocation )
    {          
          // Call getCurrentPosition with success and failure callbacks
          navigator.geolocation.getCurrentPosition( success, fail );
    }
    else
    {
          alert("Sorry, your browser does not support geolocation services.");
    }
}

 var map;
 function success(position)
 {

     var longIDText = document.getElementById('longID');
     var latIDText = document.getElementById('latID');
     longIDText.value = position.coords.longitude;
     latIDText.value = position.coords.latitude;
     document.getElementById('coordSubmitID').click();
  }

  function fail(error)
  {
          alert("FAAAAAAAAAAIIIIIIIIIL")
          var Zip_code ;
          while (true){
              // Could not obtain location

              Zip_code = Prompt("Please enter your current address or Zip code","");


              if ( Zip_code == "" ) {
                  alert(Zip_code +" is not a valid address. Please try again.");
              } 
              else{
                break;
              }
          }
          var zipIDText = document.getElementById('zipID');
          zipIDText.value = Zip_code;
          document.getElementById('coordSubmitID').click();
  }
47
theRealWorld

Pour Firefox, il semble quePERMISSION_DENIED est levé seulement si "Jamais partager" est sélectionné; si la boîte de dialogue est fermée ou si l'option "Pas maintenant" est sélectionnée, rien ne se passe effectivement, même sur démo de la géolocalisation de Mozilla si vous ignorez l'interface utilisateur des autorisations, rien ne se produit.

Cela signifie que getCurrentPosition peut renvoyer, soit parce que l'utilisateur a fermé l'interface utilisateur de confirmation, soit parce qu'il a démarré la demande asynchrone avec succès - il ne semble pas y avoir de moyen de distinguer les deux.

_ { https://bugzilla.mozilla.org/show_bug.cgi?id=675533 } _

29
Alex K.

C'est une vraie douleur, et une fonctionnalité certainement pas souhaitable.

La solution de contournement que j'utilise pour économiser l'utilisateur en attente consiste à définir un délai d'expiration pour vérifier si le compteur d'attente s'affiche au bout de 3 secondes et, le cas échéant, masquez-le et affichez une entrée manuelle du code postal:

var latlng;

var waitTime = 3000;
try {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            success(position);
        }, showError);
    } else {
        showError("NOT-SUPPORTED");
    }
    var t = setTimeout(function () {
        if ($("#getZip div.loading").css("display") != "none") {
            $("#getZip div.loading").hide();
            $("#errorZip").show();
        }
    }, waitTime);
} catch (evt) {
    alert(evt);
}
21
Jamie

Comme l'a souligné alexleonard, la seule solution fiable multi-navigateurs que j'ai trouvée consiste à avoir un setTimeout() pour vérifier l'état de votre objet/variables latLng, car l'option timeout de getCurrentPosition() ne semble pas fonctionner de manière fiable. L'exemple ci-dessous a été testé dans IE11, Chrome33 et Firefox28.

Pour une solution plus complète qui utilise une promesse jQuery, consultez mon résumé ici: https://Gist.github.com/GFoley83/10092929

Exemple - Appuyez sur F12, collez-le dans la console et exécutez

var latLng,
    geoOptions = {
        enableHighAccuracy: false,
        timeout: 5000, // Wait 5 seconds
        maximumAge: 300000 //  Valid for 5 minutes
    };

var userLocationFound = function(position){
    latLng = {
        lat: position.coords.latitude,
        lng: position.coords.longitude
    };
    window.console.log("User confirmed! Location found: " + latLng.lat + ", " + latLng .lng);
}

var userLocationNotFound = function(){
    latLng = {
        lat: -41.29247, // fallback lat 
        lng: 174.7732  // fallback lng
    };
    window.console.log("Fallback set: ", latLng);
}

window.navigator.geolocation.getCurrentPosition(userLocationFound, userLocationNotFound, geoOptions);

setTimeout(function () {
    if(!latLng){
        window.console.log("No confirmation from user, using fallback");
        userLocationNotFound();
    }else{
        window.console.log("Location was set");
    }
}, geoOptions.timeout + 1000); // Wait extra second
13
GFoley83

Notez que c'est également un problème dans Chrome.

Dans Chrome, un avis apparaît "Le site souhaite connaître votre position" - il propose ensuite les options "Autoriser" et "Refuser". Avec la conception de l'interface utilisateur, l'utilisateur est plus susceptible de choisir Autoriser ou Refuser, ce qui renverra ensuite une réponse à la fonction navigator.geolocation.getCurrentPosition. Toutefois, l'utilisateur peut également cliquer sur un "X" à l'extrême droite de la note d'information. Cela revient essentiellement à cliquer sur "Pas maintenant" dans Firefox. 

Aucun résultat n'est renvoyé à la fonction. 

Il semble qu'un minuteur doit être implémenté pour permettre ce résultat possible.

4
alexleonard

Ceci est conforme à la conception et n'est apparemment pas un problème. Voir https://bugzilla.mozilla.org/show_bug.cgi?id=675533

Il appartient aux développeurs utilisant cette fonctionnalité d’élaborer une solution de contournement spécifique à un navigateur pour Firefox.

Il est à noter que, d'après le commentaire du développeur FF sur l'utilisation réelle de la géolocalisation par les utilisateurs finaux, les développeurs de Firefox collectent apparemment des données détaillées sur les activités des utilisateurs finaux avec leurs produits.

4
Chris

Utilisez une promesse. J'utilise angularjs qui a sa propre version de $ q pour résoudre le même problème que nous avons tous.

            $scope.ByUserPosition = function () {
                //http://www.w3.org/TR/geolocation-API/
                var deferred = $q.defer();

                deferred.promise.then(findByPosition, function (data) {
                    console.log('error', data);
                });

                var resolveBy = 1000 * 30;
                navigator.geolocation.getCurrentPosition(function (position) {
                    deferred.resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude });
                }, function (err) {
                    deferred.reject(err);
                }, {
                    enableHighAccuracy: true,
                    timeout: resolveBy,
                    maximumAge: 0
                });

                $timeout(function() {
                    deferred.reject('timed out');
                }, resolveBy)
            };
3
Leblanc Meneses

La seule solution à ce problème est la suivante:

  1. Lorsque l'utilisateur clique sur le bouton pour obtenir automatiquement sa position, affichez le compteur et un lien à côté "ex: Annuler".
  2. S'il permet de partager l'emplacement, alors pas de problème. S'il décide de fermer Firefox popup, le spinner sera toujours affiché, mais il peut cliquer sur le lien "Annuler" pour arrêter le curseur et un indicateur pour fermer le popup

J'espère que ça aide :)

1
AMustafa

Modifier (après un vote négatif) 6-11-2013

Comme indiqué ci-dessous, cette réponse ne résout pas le problème lorsqu'un utilisateur refuse l'accès à la localisation. Pour le downvote est correct. Je garde la réponse ici, parce que le délai d'attente est très important, il faut l'utiliser de toute façon, et je ne le vois pas dans aucune réponse.

La fonction navigator.geolocation.getCurrentPosition () a la possibilité d’envoyer le timeout avec elle:

navigator.geolocation.getCurrentPosition(
     function (position){
        //do someting with position
     },
     function (error){
        // do something with the error (like the code)
     }, 
     {timeout:10000}
);

et d'autres options, telles que l'âge de la position mise en cache (maximumAge) . le délai d'attente et la valeur maximale sont exprimés en millisecondes, donc 10000 = 10 secondes.

Soit dit en passant, le délai d’expiration par défaut est infini ... donc, si vous ne le définissez pas, il n’appellera jamais le rappel pour les erreurs ....

donc dans l'option comme Jamie a répondu, je dirais:

if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            success(position);
        }, showError, {timeout:3000});
    }
1
michel.iamit

Voici une solution à mon problème avec Vanilla es6 Promises. Inspiré par la réponse de @LeblancMeneses.

if(navigator.geolocation) {
  let promise = new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        resolve(position)
      },
      (error) => {
        resolve(error)
      }
    )
    window.setTimeout(() => {
      resolve({})
    }, 8000)
  })
  promise.then((result) => {
      // do something with result
  })
} else {
  console.log('no geolocation available')
}
0
Harry Moreno