entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

3votos

Obtener valor desde otro método

Hola gente, estoy aprendiendo javascript y estoy bastante confundido, soy programador java, y me resultan extraños los métodos asíncronos jajaja.

Pues bien, tengo el siguiente código que me devuelve la dirección de mi ubicación:

function getActualLocation() {
var options = {timeout: 30000, enableHighAccuracy: true};
navigator.geolocation.getCurrentPosition(sucessPosition , errorPosition, options);
}

function sucessPosition(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;

var reverseGeocoder = new google.maps.Geocoder();
var currentPosition = new google.maps.LatLng(latitude, longitude);
reverseGeocoder.geocode({'latLng': currentPosition}, function (results, status) {

 if (status == google.maps.GeocoderStatus.OK) {
     if (results[0]) {
         direccion = results[0].formatted_address;
      } else {
          navigator.notification.alert('Error');
      }
  } else {
      navigator.notification.alert('Error');
  }
});
}

function errorPosition() {
    navigator.notification.alert('Error');
}

Todo funciona correcto y como veis tengo una variable "direccion" con el valor que necesito. El problema esque al ser una petición asíncrona se pierde el valor al salir de la función y lo necesito en otra función en la cual le paso una serie de datos a un web service.

He probado a que dirección sea una variable global al principio del .js pero veo que tampoco funciona y sigo obteniendo "undefined".

A ver si podeis aclararme un poco el tema. Gracias.

4 Respuestas

2votos

CarmaZone Puntos1110

Perdón por no contestar antes pero encontré una solución y he estado liado en el trabajo y no he podido poner la solución.

juansolo, no probé tú código porque me funcionaba lo otro, aunque la verdad es la primera vez que veo lo de "use strict" y fn() jajaja. Cosas de ser noob javascript. Sin embargo, si conoces algún tutorial para aprender éstas cosas y similares me vendría bien :D

La solución al final era meterlo en una variable global, sin embargo se perdía antes de que se asignara y comentándoselo a un amigo me dijo que probará la llamada antes de un timeout y así fue.

Función obtener localicación simplificada:

    function getLocation() {
        if (!navigator.geolocation)
            return;

        navigator.geolocation.getCurrentPosition(function (pos) {
            geocoder = new google.maps.Geocoder();
            var latlng = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude);
            geocoder.geocode({'latLng': latlng}, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    _direccionActual = results[0].formatted_address;
                }
            });
        });
    }

Función de llamada:

function fill() {
    getLocation();
    setTimeout(function () {
        notificar();
    }, 6000);
}

De esa forma llamando a getLocation() puedo asignar la variable global gracias al timeout para posteriormente usarla en notificar() que es dónde la necesitaba.

Tal vez no sea lo más óptimo/correcto pero me ha funcionado y por ahora me vale jejeje.

0voto

Peter comentado

Si esta es la solución, por favor selecciona la respuesta como correcta.

Saludos.

0voto

juansolo comentado

Hola, fijate en una cosa si la llamada asíncrona por algún motivo tarda en responder más del tiempo que has especificado (el timeout es mayor), al usar una variable global estarás usando un valor anterior.

Javascript es un lenguaje muy "libertino". "use strict" evita esto y te suele ahorrar bonitos dolores de cabeza.

Tú problema se resuelve usando callbacks. "fn" representa un callback que no es más que una función a través de la cual exportas datos hacia el exterior.

1voto

Leonardo-Tadei Puntos227010

Hola CarmaZone,

el problema parece ser de ámbito de las variables. Para JavaScript, toda variable definida dentro de una función es local a ella, pero accecible desde sus funciones anidadas.

En este caso debería bastar con que al principio de código definas:

var direccion = '';

(con el var delante). De esta format u función sucessPosition() usará la variable del entorno superior en vez de crear una local.

Luego, podés usar como bandera el contenido de esta misma variable para saber cuando usarla con esta pequeña modificación:

var direccion = '';
function sucessPosition(position) {
direccion = '';
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;

var reverseGeocoder = new google.maps.Geocoder();
var currentPosition = new google.maps.LatLng(latitude, longitude);
reverseGeocoder.geocode({'latLng': currentPosition}, function (results, status) {

 if (status == google.maps.GeocoderStatus.OK) {
     if (results[0]) {
         direccion = results[0].formatted_address;
      } else {
          direccion = '';
          navigator.notification.alert('Error');
      }
  } else {
      direccion = '';
      navigator.notification.alert('Error');
  }
});
}

Es decir, la ponés en blanco al invocar a la función y también al devolver error la consulta, de forma tal que si está en blanco no hay nada que hacer, y si tiene un valor sí.

Contanos cómo te fue con esto!

0voto

CarmaZone comentado

Gracias, pero no funciona, en el momento que sale de la función interna

reverseGeocoder.geocode({'latLng': currentPosition}, function (results, status) {

se pierde el valor. https://db.tt/DNVAcFmr

0voto

Leonardo-Tadei comentado

No había visto que esa llamada invocaba una función anónima, que tiene una profundidad más de anidamiento de la estructura. El valor queda local a dicha función anónima...

No te devuelve la función reverseGeocoder.geocode() el valor que se procesó dentro???

0voto

CarmaZone comentado

Efectivamente, el valor queda local a esa función anónima. ¿Cómo puedo comprobar si lo devuelves como comentas? reverseGeocoder.geocode() hace una petición asíncrona. Necesitaría sacar el valor fuera de la anónima interior a una variable global. ¿Alguna forma usando callback o similar?

0voto

Leonardo-Tadei comentado

Yo en lo posible trato de no usar funciones anónimas, porque la cuestión del ámbito de las variables se vuelve un infierno... pero bueno, no me tomes cómo referencia, porque me llevo bastante mal con JavaScript: lo uno muchísimo, escribo mucho código, pero no hay caso que me guste.

La solución que pone @LxDAndromeda tiene muy buena pinta: al definir la variable como miembo de window y al estar este objeto presente en todas partes, deberías poder asignarle el valor y usarlo más tarde... otra cosa es la cuestión de la sincronía: tal vez cuando quieras usarlo todavía no tenga el valor asignado, porque el proceso de geolocalización tarda.

1voto

LxDAndromeda Puntos2440

Cambia:

direccion = results[0].formatted_address;

Por:

window.direccion = results[0].formatted_address;

Luego, utiliza window.direccion en cualquier parte del código que lo necesites.

1voto

juansolo Puntos1840

Prueba haciendo lo siguiente:

"use strict";
function sucessPosition(position, fn {
    var latitude = position.coords.latitude,
        longitude = position.coords.longitude,
        reverseGeocoder = new google.maps.Geocoder(),
        currentPosition = new google.maps.LatLng(latitude, longitude),
        la_direccion = '';

    reverseGeocoder.geocode({'latLng': currentPosition},
                            function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[0]) {
                la_direccion = results[0].formatted_address;
            } else {
                la_direccion = '';
            }
        } else {
            la_direccion = '';
        }
        fn(la_direccion);
    });
});

//LLAMADA
sucessPosition(position, function(la_direccion) {
    if(la_direccion) {
        //Hacer algo maravilloso con la dirección
    } else {
      navigator.notification.alert('Error');
    }
});

Simplemente defines un callback para obtener el valor y luego propagarlo hacia el exterior.

El uso de una variable global en este caso es muy peligroso pues tienes código sincrono que realiza una llamada asíncrona. Si te fijas, cuando la función se ejecuta no se para en la llamada sino que continua por eso siempre se recomienda usar callbacks.

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta