Tutorial de Ionic – Crear una aplicación para guardar nuestros sitios geolocalizados – Parte 4 – Mostrando la dirección a partir de las coordenadas y sacando foto con la cámara.

En el siguiente enlace tienes el índice para acceder al resto de entradas de este tutorial:

 

¡¡Atención!! este tutorial se basa en ionic 3 y está desactualizado por lo que es posible que los ejemplos no funcionen en la última versión de ionic, haz click aquí para acceder a un tutorial mas actual de Ionic.

Hola a todos:

En el post anterior vimos como poner un marcador al mapa, aprendimos a utilizar los botones FAB y aprendimos a utilizar ventanas modales.

Hoy vamos a continuar desarrollando nuestra app, vamos a crear un pequeño formulario en el modal donde mediante una llamada a la api de google maps obtendremos y mostraremos la dirección a partir de las coordenadas y permitiremos introducir una descripción y  también tomar una fotografía del lugar.

Bien, vayamos por partes:

Ahora vamos a añadir al controlador del modal tres variables nuevas que vamos a necesitar:

  • Una variable de tipo string  que vamos a llamar address donde guardaremos la dirección que luego mostraremos en la vista.
  • Una variable de tipo string a la que vamos a llamar description y que contendrá la descripción del lugar que introduzcamos desde el formulario.
  • Por último una variable de tipo any que vamos a llamar foto, donde guardaremos una foto del lugar codificada en base 64.

Por lo tanto editamos el controlador de nuestro modal (modal-nuevo-sitio.ts) encima del constructor de la clase después de la variable coords definimos las siguientes variables:

...

export class ModalNuevoSitioPage {

  coords : any = { lat: 0, lng: 0 }
  address: string;
  description: string = '';
  foto: any = '';

  constructor(public navCtrl: NavController, public navParams: NavParams, private viewCtrl : ViewController) {}

...

Para obtener la dirección correspondiente a unas coordenadas Google maps cuenta con el elemento Geodecoder. 

Vamos a ver brevemente como funciona Google Maps  Geodecoder:

Para realizar una petición debemos crear un objeto dela clase Geodecoder y llamar al método geodecode pasandole las coordenadas y una función callback donde recibimos los datos en caso de tener éxito y el estado de la petición:

var geocoder = new google.maps.Geocoder();

geocoder.geocode({'location': coords} , function (results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
       // en results tenemos lo que nos devuelve la llamada;
    } else {
      // Ha habido algún error
    }
});

Para obtener los resultados tenemos pasarle una función callback, sin embargo lo que nos interesa en que nos devuelva una promesa que es la mejor manera de gestionar las peticiones asíncronas desde el controlador.

Tabla de contenidos

Creando nuestras propias promesas

Ya vimos en el capitulo anterior como se tratan las funciones que nos devuelve una promesa utilizando then, pero si queremos que una función que creemos nosotros devuelva una promesa tenemos que devolver un objeto Promise donde la promesa se crea a partir de una función callback en el que ejecutaremos la sentencia que nos devolverá el resultado asíncrono y  llamaremos a las funciones pasadas como argumento resolve y reject. Si la operación se a ejecutado correctamente se llama a resolve, y si a ocurrido un error llamamos a reject.

Sabiendo esto para conseguir que geodecode nos devuelva la dirección en una promesa tenemos que utilizar un pequeño truco que consiste en crear una función que vamos a llamar getAddress y que haremos que nos devuelva una promesa con el resultado de la llamada a geodecode, para ello editamos el archivo modal-nuevo-sitio.ts añadimos la siguiente función en el controlador:

getAddress(coords):any {
    var geocoder = new google.maps.Geocoder();

    return new Promise(function(resolve, reject) {
        geocoder.geocode({'location': coords} , function (results, status) { // llamado asincronamente
            if (status == google.maps.GeocoderStatus.OK) {
                resolve(results);
            } else {
                reject(status);
            }
        });
    });
}

Como podemos ver la función retorna una promesa donde se le pasa como parámetro una función con resolve y reject, luego dentro de la función se ejecuta la llamada a geodecoder.geodecode pasándole las coordenadas y la función callback donde si se ha recibido como status google.maps.GeocoderStatus.OK significa que hemos recibido correctamente los datos y entonces ejecutamos resolve, de lo contrario ejecutamos reject.

De esta manera podemos hacer que geodecode nos devuelva una promesa.

Nota: al igual que hicimos en la pagina de inicio, para que Typescript no de error por no reconocer la clase google cuando la llamemos desde la función que vamos a crear, vamos a declarar la variable google justo debajo de los imports con declare var google: any; 

Ahora en el método ionViewDidLoad que se ejecuta cuando la página se ha cargado vamos ha hacer una llamada a getAddress pasándole las coordenadas que hemos recibido para obtener la dirección y asignársela a this.address:

ionViewDidLoad() {
    console.log('ionViewDidLoad ModalNuevoSitioPage');
    this.coords.lat = this.navParams.get('lat');
    this.coords.lng = this.navParams.get('lng');
   this.getAddress(this.coords).then(results=> {
        this.address = results[0]['formatted_address'];
      }, errStatus => {
          // Aquí iría el código para manejar el error
      });
  }

Un ejemplo de la estructura de datos que recibimos en results sería:

{
 "results": [ {
 "types": street_address,
 "formatted_address": "Etorbidea Abandoibarra, 2, 48001 Bilbo, Bizkaia, España",
 "address_components": [ {
 "long_name": "2",
 "short_name": "2",
 "types": street_number
 }, {
 "long_name": "Etorbidea Abandoibarra",
 "short_name": "Etorbidea Abandoibarra",
 "types": route
 }, {
 "long_name": "Bilbo",
 "short_name": "Bilbo",
 "types": [ "locality", "political" ]
 }, {
 "long_name": "Bizkaia",
 "short_name": "BI",
 "types": [ "administrative_area_level_2", "political" ]
 }, {
 "long_name": "Euskadi",
 "short_name": "PV",
 "types": [ "administrative_area_level_1", "political" ]
 }, {
 "long_name": "España",
 "short_name": "ES",
 "types": [ "country", "political" ]
 }, {
 "long_name": "48001",
 "short_name": "48001",
 "types": postal_code
 } ],
 "geometry": {
 "location": {
 "lat": 43.26861,
 "lng": -2.934380000000033
 },
 "location_type": "ROOFTOP",
 "viewport": {
 "southwest": {
 "lat": 43.26726101970851, 
 "lng": -2.9357289802915147
 },
 "northeast": {
 "lat": 43.26995898029151,
 "lng": -2.933031019708551
 }
 }
 }
 } ]
}

Lo que nos interesa obtener que es la dirección completa se encuentra en results[0][‘formatted_address’], por lo tanto  le asignamos este dato a this.address.

Mostrando las coordenadas y la  dirección.

Ahora vamos a añadir en la vista un componente ion-card  donde mostraremos las coordenadas y la dirección donde nos encontramos, editamos el archivo modal-nuevo-sitio.html para que quede de la siguiente manera:

<!--
  Generated template for the ModalNuevoSitio page.

  See http://ionicframework.com/docs/v2/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar>
    <ion-title>Nuevo sitio</ion-title>
    <ion-buttons start>
      <button ion-button (click)="cerrarModal()">
        <ion-icon name="md-close"></ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>

</ion-header>

<ion-content padding>
  <ion-card>
    <ion-card-header>
      Localización actual
    </ion-card-header>
    <ion-card-content>
      <p><strong>lat:</strong>{{ coords.lat}}<br/>
      <strong>lng:</strong>{{coords.lng }}</p>
      <hr>
      <p>{{ address }}</p>
    </ion-card-content>
  </ion-card>
</ion-content>

Como podéis observar hemos creado un componente ion-card que consta a su vez de un elemento ion-card-header donde ponemos como título “Localización  actual”, y en ion-car-content pondremos el contenido que queremos mostrar, en este caso mostramos un elemento <p> donde mostramos el valor de las variables coords.lat y coords.lng que hemos definido en el controlador y que contendrán las coordenadas actuales.

Por otro lado mostramos otro elemento <p> con el contenido de la variable address que de momento no contiene nada pero que contendrá la dirección que corresponda con las coordenadas que hemos recogido.

Al pulsar en el FAB se abrirá el modal mostrando algo similar a esto:

Modal con las coordenadas y a dirección
Modal con las coordenadas y a dirección

Creando el formulario.

Vamos a seguir añadiendo elementos a la vista del modal. Además de las coordenadas y la dirección queremos dar la posibilidad de tomar una foto del lugar y escribir anotaciones.
Para ello vamos a crear dentro del card, debajo de la dirección un pequeño formulario donde habrá un botón para sacar una foto y un campo text-area para  escribir una descripción del lugar.

Editamos de nuevo modal-nuevo-sitio.html y añadimos lo que está marcado de amarillo:

<!--
  Generated template for the ModalNuevoSitio page.

  See http://ionicframework.com/docs/v2/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar>
    <ion-title>Nuevo sitio</ion-title>
    <ion-buttons start>
      <button ion-button (click)="cerrarModal()">
        <ion-icon name="md-close"></ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>

</ion-header>

<ion-content padding>
  <ion-card>
    <ion-card-header>
     <strong>Localización actual</strong>
    </ion-card-header>
    <ion-card-content>
      <p><strong>lat:</strong>{{ coords.lat}}<br/>
      <strong>lng:</strong>{{coords.lng }}</p>
      <hr>
      <p>{{ address }}</p>
      <hr/>
      <form (ngSubmit)="guardarSitio()">
      <ion-item>
        <img [src]="foto" *ngIf="foto" />
        <button ion-button icon-left full type="button" (tap)="sacarFoto()">
          Foto&nbsp;&nbsp;
          <ion-icon name="camera"></ion-icon>
        </button>
      </ion-item>
      <hr/>
      <ion-item>
        <ion-label>Descripción</ion-label>
        <ion-textarea [(ngModel)]="description" name="description"></ion-textarea>
      </ion-item>
      <button ion-button type="submit" block>Guardar Sitio</button>
    </form>
    </ion-card-content>
    </ion-card>
</ion-content>

Como vemos al formulario le hemos añadido (ngSubmit), con esto le indicamos que cuando se ejecute el evento submit del formulario se ejecute la función guardarSitio definida en el controlador.

Después hemos añadido un elemento ion-item, donde vamos a mostrar la imagen con la fotografía que tomemos:

 <img [src]="foto" *ngIf="foto" />

Por un lado con [src] le indicamos que la imagen va a mostrar lo que contenga la variable foto, que hemos definido el el controlador y que al principio estará vacía, y por otro lado con *ngIf le indicamos que solo se muestre la imagen si dicha variable foto tiene un valor, es decir que solo se mostrará una vez hayamos tomado la fotografía.

Después tenemos un botón que al pulsar llama a la función sacarFoto que después definiremos en el controlador:

<button ion-button icon-left full type="button" (tap)="sacarFoto()">
          Foto&nbsp;&nbsp;
          <ion-icon name="camera"></ion-icon>
 </button>

Con icon-left le indicamos al botón que el icono se situará a la izquierda, para mostrar el icono después del texto “Foto” y un par de espacios en blanco “&nbsp;” insertamos el elemento ion-icon con  el icono camera.

Después tenemos un campo de tipo ion-textarea donde podremos introducir la descripción del sitio:

<ion-item>
    <ion-label>Descripción</ion-label>
    <ion-textarea [(ngModel)]="description" name="description"></ion-textarea>
</ion-item>

Por último tenemos un botón de tipo submit para enviar el formulario. Recordad que cuando pulsemos en este botón se disparará el evento ngSubmit y por lo tanto se ejecutará la función guardarSitio tal y como hemos definido en la etiqueta form.

Utilizando la cámara del teléfono móvil

Ahora vamos a ver como sacar una foto y para que se muestre en la etiqueta img que hemos creado:

Para poder utilizar la cámara del móvil tenemos que instalar el plugin cordova-plugin-camera con el siguiente comando:

ionic cordova plugin add cordova-plugin-camera --save
npm install --save @ionic-native/camera

Ahora el controlador del modal (modal-nuevo-sitio.ts) tenemos  que importar Camera desde ionic-native e inyectarlo en el constructor:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';
import { Camera, CameraOptions } from '@ionic-native/camera';

declare var google:any;
/**
 * Generated class for the ModalNuevoSitio page.
 *
 * See http://ionicframework.com/docs/components/#navigation for more info
 * on Ionic pages and navigation.
 */

@IonicPage()
@Component({
  selector: 'page-modal-nuevo-sitio',
  templateUrl: 'modal-nuevo-sitio.html',
})
export class ModalNuevoSitioPage {

  coords : any = { lat: 0, lng: 0 }
  address: string;
  description: string = '';
  foto: any = '';

  constructor(public navCtrl: NavController, public navParams: NavParams, private viewCtrl : ViewController, private camera: Camera) {
  }
...

También debemos importar Camera en app.module.ts y declararlo como provider:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { Geolocation } from '@ionic-native/geolocation';
import { Camera } from '@ionic-native/camera';

import { MyApp } from './app.component';


@NgModule({
  declarations: [
    MyApp,
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},Geolocation,Camera
  ]
})
export class AppModule {}

Ahora vamos a crear el método sacarFoto en en el controlador (modal-nuevo-sitio.ts) que se ejecutará al pulsar sobre el botón Foto.

En el archivo modal-nuevo-sitio.ts añadimos el siguiente código dentro del controlador:

sacarFoto(){

    let cameraOptions : CameraOptions = {
        quality: 50,
        encodingType: this.camera.EncodingType.JPEG,
        targetWidth: 800,
        targetHeight: 600,
        destinationType: this.camera.DestinationType.DATA_URL,
        sourceType: this.camera.PictureSourceType.CAMERA,
        correctOrientation: true
    }


    this.camera.getPicture(cameraOptions).then((imageData) => {
      // imageData is a base64 encoded string
        this.foto = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });
  }

Para sacar una foto utilizamos el método getPicture pasándole un array de opciones. En las opciones definimos las características que va a tener la imagen:

  • encodingType: Selecciona la codificación del archivo de imagen devuelto, puede ser JPEG o PNG.
  • targetWidth: Anchura de la foto.
  • targetHeight: Altura de la foto.
  • destinationType: Define el formato del valor devuelto, puede ser :
    • DATA_URL devuelve la imagen como una cadena codificada en base64.
    • FILE_URI: Crea un archivo con la imagen y devuelve la ruta al archivo.
    • NATIVE_URI: devuelve la ruta nativa al archivo (assets-library:// en iOS o content:// en Android).
  • sourceType: Indica el origen de la foto, puede ser:
    • CAMERA (por defecto).
    • PHOTOLIBRARY
    • SAVEDPHOTOALBUM
  • correctOrientation: Gira la imagen para corregir la orientación del dispositivo durante la captura.

Puedes visitar el siguiente enlace para conocer todas las opciones posibles y saber más sobre el plugin Camera:

https://ionicframework.com/docs/native/camera/

En this.foto guardamos la imagen codificada en formato base64 que recibimos de la cámara, para poder mostrarla como parte de la url en el parámetro src de la imagen tenemos que añadirle “data:image/jpeg;base64,” por delante.

Por si alguno se ha perdido muestro el contenido completo de como tiene que quedar en estos momentos el archivo modal-nuevo-sitio.ts:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams,  ViewController } from 'ionic-angular';
import { Camera, CameraOptions } from '@ionic-native/camera';

declare var google:any;

/*
  Generated class for the ModalNuevoSitio page.

  See http://ionicframework.com/docs/v2/components/#navigation for more info on
  Ionic pages and navigation.
*/
@IonicPage()
@Component({
  selector: 'page-modal-nuevo-sitio',
  templateUrl: 'modal-nuevo-sitio.html'
})
export class ModalNuevoSitioPage {

  coords : any = { lat: 0, lng: 0 }
  address: string;
  description: string = '';
  foto: any = '';

  constructor(public navCtrl: NavController, public navParams: NavParams, private viewCtrl : ViewController, private camera: Camera ) {}

  ionViewDidLoad() {
    console.log('ionViewDidLoad ModalNuevoSitioPage');
    this.coords.lat = this.navParams.get('lat');
    this.coords.lng = this.navParams.get('lng');
    this.getAddress(this.coords).then(results=> {
        this.address = results[0]['formatted_address'];
      }, errStatus => {
          // Aquí iría el código para manejar el error
      });
  }

  cerrarModal(){
    this.viewCtrl.dismiss();
  }

  getAddress(coords):any {
    var geocoder = new google.maps.Geocoder();

    return new Promise(function(resolve, reject) {
        geocoder.geocode({'location': coords} , function (results, status) { // llamado asincronamente
            if (status == google.maps.GeocoderStatus.OK) {
                resolve(results);
            } else {
                reject(status);
            }
        });
    });
  }

  sacarFoto(){

    let cameraOptions : CameraOptions = {
        quality: 50,
        encodingType: this.camera.EncodingType.JPEG,
        targetWidth: 800,
        targetHeight: 600,
        destinationType: this.camera.DestinationType.DATA_URL,
        sourceType: this.camera.PictureSourceType.CAMERA,
        correctOrientation: true
    }


    this.camera.getPicture(cameraOptions).then((imageData) => {
      // imageData is a base64 encoded string
        this.foto = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });
  }

}

Añadiendo plataformas

Bien, hasta ahora hemos estado probando nuestra aplicación en el navegador, sin embargo no podemos probar el plugin camera desde el navegador. Ha llegado la hora de probar nuestra aplicación en un dispositivo móvil.

Lo primero que tenemos que hacer es añadir la plataforma en la que queremos probar nuestra aplicación.

Para añadir una plataforma utilizamos el siguiente comando desde consola, recordad que debemos esta siempre dentro de la ios
ionic platform add wp

Por lo tanto si queremos probar nuestra app en android escribiremos:

ionic cordova platform add android

Esto nos creará una carpeta llamada platforms si no estaba creada, y añadirá una carpeta android con todo el código necesario para poder generar un archivo apk instalable.

En Mac y Linux tal vez os pida que escribáis sudo por delante.

Ejecutando nuestra app en el dispositivo móvil

Una vez tenemos añadida la plataforma si enchufamos nuestro móvil con un cable usb a nuestro pc podemos ejecutar la app directamente en el dispositivo con el siguiente comando:

ionic cordova run android

Si no disponéis de un dispositivo también podéis emular la aplicación utilizando ionic emulate:

ionic cordova emulate android

En ios también puedes entrar en la carpeta  platforms/ios y abrir el archivo con extensión .xcodeproj desde Xcode y ejecutarlo o emularlo desde Xcode.

El el móvil la app con el modal abierto se vería algo así:

Nuestra App funcionando en un dispositivo móvil.
Nuestra App funcionando en un dispositivo móvil.

Como podéis observar mi gato se ha prestado voluntariamente para posar en la foto ;-P

Dependiendo del sistema operativo que utilicéis en vuestro pc y del dispositivo puede que tengáis algún  problema para que os reconozca el móvil, yo no tengo tiempo de investigar cada caso pero googleando seguro que dais con la solución,  os animo a que dejéis en los comentarios si tenéis algún problema y que quién encuentre la solución lo ponga para ayudarnos unos a otros.

Por hoy lo dejamos aquí, en el siguiente capitulo veremos como guardar nuestros sitios en una base de datos local en nuestro dispositivo.

 

Si necesitas desarrollar una aplicación móvil no dudes en solicitarme un presupuesto sin compromiso:

Un saludo, y si aún no lo has hecho no olvides suscribirte a mi blog para no perderte los próximos posts  :-),

También puedes seguirme en Twitter en ‎@revigames y no olvides que me ayudas mucho si compartes este post en las redes sociales.

31 comentarios en “Tutorial de Ionic – Crear una aplicación para guardar nuestros sitios geolocalizados – Parte 4 – Mostrando la dirección a partir de las coordenadas y sacando foto con la cámara.

  1. buenas amigo saludos.

    tengo una duda cuando se debe mostrar la dirección, solo estoy confundido, tu comentas que por el momento la variable addres no contiene nada y cuando muestras la imagen de la app se muestra la dirección. y cuando ejecuto mi aplicación no me muestra la dirección

    1. Hola gamster12,
      Tienes razón, en el listado final del código de modal-nuevo-sitio.ts si se hace la llamada a la función this.getAddress para obtener la dirección y asignársela a la variable address en ionViewDidLoad, sin embargo es cierto que se me había olvidado explicarlo, he editado la entrada para añadir esta explicación.
      Muchas gracias por advertirme 🙂

      Un saludo

  2. Hola, muchas gracias una vez más por tal estupendo tutorial.

    Me gustaría añadir un par de cosas, y es que al igual que en un post anterior, para los que utilizamos SO windows, debemos declarar en el script modal-nuevo-sitio.ts la línea: declare var google: any; justo después de los imports.
    Quedando de este modo:

    import { Component } from ‘@angular/core’;
    import { NavController, NavParams, ViewController } from ‘ionic-angular’;

    declare var google: any;

    @Component({
    selector: ‘page-modal-nuevo-sitio’,
    templateUrl: ‘modal-nuevo-sitio.html’
    })

    Por otro lado, cuando pulso sobre el botón para llamar a la cámara en mi iphone 5 funciona perfectamente. Pero tras hacer la foto pinta un cuadradito blanco, no muestra la imagen.
    ¿Alguien sabe a qué se debe?

    Ah una cosa más… un saludo a tu gato, buena pose muestra 🙂

    1. Hola Luis,
      Ya he añadido la linea “declare var google:any;”
      Una vez más gracias por el aporte, en cuanto al problema que te da en tu iPhone 5 no se a que se puede deber, yo las pruebas las he estado haciendo en Android, pero tras leer tu comentario he probado en un iPhone 6 que tengo y la foto se ve correctamente.
      ¿Solo por curiosidad, como ejecutas la app en tu iPhone desde Windows?

      Un saludo

      1. Voy sacando más conclusiones.
        Viendo que no era capáz de reproducir el error, he vuelto a hacer el proyecto completo y lo he comprobado con el mismo dispositivo móvil, un iphon 5. El resultado ha sido el mismo. Por lo tanto, he descargado ionic viewer en mi samsung galaxy tab2 y ahí funciona. Hago la foto y se muestra en el recuadro cosa que con el iphone5 se muestra el recuadro vacío, como si la ruta de la imagen fuera errónea.

        Continúo investigando.
        Saludos!

  3. Buenas tardes, primero felicitar por el magnifico tutorial, muy bien explicado y de manera sencilla. Solo me queda una duda. Cuando emulo la aplicacion todos los servicios funcionan bien pero cuando lo corro en un dispositivo android la geolocalizacion no me funciona, ni siquiera me da ningun error y por consiguiente el mapa tampoco nunca se abre, si pudiera darme una pista de que pudiera ser estaria muy agradecido.
    Saludos

  4. Hola, muchas felicidades por tan buen tutorial y muy bien explicado, solo me queda una duda y es que cuando estoy emulando la apliacion todo funciona bien, pero cuando la corro en un dispositivo android la geolocalizacion no funciona. Probe creando otra aplicacion y solo utilizando la funcionalidad que pondre debajo, que se ejecuta cuando oprimo un boton por si era problema de que no le habia dado tiempo a cargar toda la aplicacion:
    this.geolocation.getCurrentPosition().then((resp) => {
    console.log(‘resp: ‘, resp);

    this.latitude = resp.coords.latitude;
    this.longitude = resp.coords.longitude;
    }).catch((error) => {
    console.log(‘Error getting location’, error);
    });
    En fin nunca entra ni al console.log del then ni del catch, ejecuto otras aplicaciones que necesitan localizacion del celular y funcionan perfectamente y como no me devuelve ningun error solo me queda preguntar a personas con mas experiencias.
    Gracias de antemano por la ayuda que pueda brindarme y por el magnifico tutorial.

    1. Hola llaublog, voy a intentar ayudarte sin tener mucha experiencia.
      Pon un alert dentro del then y otro dentro del catch. Este del catch que sea alert(error);
      De este modo sabremos que te falla.
      Nos cuentas qué tal.

  5. dentro del then y el catch tengo par de console.log, el del then por si le ejecucion fue positiva me muestra el resultado y el del catch me devuelve el error pero el tema es que no me devuevle ninguno de los dos console.log, es como que nunca ejecuta esa promesa, sin embargo en la linea inmediata superior a esta tengo otro console.log para ver si llega ahi y ese si me retorna

  6. Para los que no les sirve la camara en Android.

    Recuerden importar import { Camera } from ‘@ionic-native/camera’; en app.module.ts , ademas de declararlo como providers como así lo hicieron con la Geolocalizacion.

  7. Hola Eduardo.
    Magnífico tutorial, muchas gracias.
    He estado siguiendo todos los pasos, y a la hora de ejecutarlo en el móvil, cuando pincho en el botón para pasar al modal, me lo abre, pero a la hora de clickar en él, no me hace nada.

  8. Hola Eduardo.
    Magnífico tutorial, muchas gracias.

    Siguiendo el tutorial, al ejecutar la aplicación en mi móvil, cuando llego a la vista del modal, pincho en el botón de la foto, y no hace nada.

    1. Hola zenk4276, tal y como ha apuntado Jhon en el comentario de arriba, probablemente te falte importar y declarar Camera en app.module.ts, he modificado el tutorial para añadir este import, gracias por comentar.

  9. Buenas noches, ante todo felicitaciones por el tutorial, realmente excelente.
    Escribo porque estoy teniendo un problema con el map. Lo puedo visualizar en web (serve -l) pero cuando lo instalo en mi telefono Android el mapa no se visualiza… no veo errores en el log, y puedo usar la cámara sin problemas… Ideas de cómo resolver el problema?
    Saludos
    Nico

    1. Actualizo las novedades de mi error, el problema esta en this.geolocation.getCurrentPosition().then(….). EL metodo nunca termina de ejecutarse, por lo tanto no entra al then, tampoco al catch…

      1. hola NIcolas!! Estoy siguiendo este tutorial y tengo el mismo problema con el map, lo puedo visualizar en web pero en android el mapa no se despliega. Tu pudiste resolver el problema?? podrías compartir conmigo tu solución.
        Gracias, saludos

  10. Una pregunta, soy nuevo con el framework de ionic, y mi primera app, va a ser esta. Me podrías explicar un poco más extendido que es lo que hace getAddress con la promesa.

    1. Hola David, las promesas no son parte de ionic como tal si no que forman parte de javascript. Las promesas nacieron para sustituir a los callback, los callback se pasan como parámetro y se ejecutan cuando se obtiene un resultado, sin embargo muchas veces se apilaban llamadas a funciones con callbacks y mas callbacks y esto hacia que se formase la famosa pirámide de la muerte.
      Con las promesas en lugar de pasar una función callback como parámetro a una función para que se ejecute cuando la función haya obtenido los resultados simplemente llamamos a then() y podemos apilar las distintas llamadas asincronas de una manera más fácil de leer.

      En este caso me me consultas el método geodecode no devuelve una promesa si no que espera que le pases una función callback para que se ejecute cuando obtiene la dirección.

      En la función que hemos creado con return new Promise estamos devolviendo una promesa, cuando creamos una promesa como parámetro le pasamos una función que recibe resolve y reject. Llamamos a resolve si todo a ido bien devolviendo el resultado y si ha habido algún error llamamos a reject.

      De esta manera cuando llamamos a getAddress no tenemos que pasarle un callback para que se ejecute al obtener la dirección sino que directamente nos devuelve una promesa que recibimos en .then().

      Si quieres saber más como funcionan las promesas puedes echar un vistazo a este enlace:
      https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise

      Un saludo

  11. Para los que tengan problemas con la camara y les sale el cuadro de mensaje una ves estando a la camara solo desconecten el usb o cable del celular , ya que estando no funciona despues de ello reinicien su celular y vuelvan abrir la aplicacion, Espero y les sirva!!

  12. lo unico que me quedo duda fue lo de la direccion , como le hago para que me aparezca por que me aparece en blanco y nose si asi debe aparecer o me equivoque en algo, agradecería mucho si alguien me aclarará esa duda porfa

  13. Hola, excelente pero tengo una gran duda. Es posible, ya que tienes las coordenadas en el modal, desplegar un mapa, con esas coordenadas? He probado de muchas formas y no hay caso que se despliegue el mapa. Tampoco parece funcionar en oaginas que estan estructuradas como SLIDES……

    1. Hola Manuel,

      Se puede mostrar un mapa en el modal si lo deseas.
      Tienes que crear un div en la vista donde se mostrará el mapa. A ese div dale un id diferente que el que tienes en la pagina de inicio para que no haya conflictos por ejemplo:
      <div id=”map2″></div>
      En el archivo scss del modal tienes que darle un tamaño, por ejemplo:

      page-modal-detalle-sitio {
      ion-content{
      #map2 {
      width: 100%;
      height: 50%;
      }
      }
      }

      Y en el controlador debes crear una función para crear al mapa con las coordenadas del sitio y llamarlo en la función onViewDidload, por ejemplo podría ser algo así:

      ionViewDidLoad() {
      console.log(‘ionViewDidLoad ModalDetalleSitioPage’);
      this.loadMap()
      }

      loadMap(){
      let mapContainer = document.getElementById(‘map2’);
      this.map = new google.maps.Map(mapContainer, {
      center: { lat: this.sitio.lat, lng: this.sitio.lng},
      zoom: 12
      });

      // Colocamos el marcador
      let miMarker = new google.maps.Marker({
      icon : ‘assets/img/ico_estoy_aqui.png’,
      map: this.map,
      position: { lat: this.sitio.lat, lng: this.sitio.lng}
      });

      }

      Por ultimo no olvides declarar antes del constructor la variable map:


      export class ModalDetalleSitioPage {

      sitio: any;
      map: any;

      constructor(

      Espero que te sea de ayuda.

      Un saludo

  14. hola eduardo buen dia,

    si ya tengo las coordenadas fijas, las extraigo de un servidor, como puedo hacer para que me muestre la direccion en base a las cordenas,

    saludos.

    1. Hola gamster12, pues simplemente llamando a la función getAddress pasandole las coordenadas que has obtenido del servidor, podría ser algo así:

      Suponiendo que tenemos definida la variable coords y address como miembro de la clase antes del constructor:

      coords : any = { lat: 0, lng: 0 }
      address: string;

      Después para obtener la dirección utilizas:

      this.coords.lat = ‘aquí le asignas la latitud de la coordenada obtenida del servidor’;
      this.coords.lng = ‘aquí le asignas la longitud obtenida del servidor’;
      this.getAddress(this.coords).then(results=> {
      this.address = results[0][‘formatted_address’];
      }, errStatus => {
      // Aquí iría el código para manejar el error
      });

      Por último en la plantilla html donde quieras mostrar la dirección:
      {{ address }}

      Un saludo

  15. Buenas, he seguido el tutorial al pie de la letra (incluso más adelante cuando comienzas a explicar Firebase). El caso es que el código para extraer el field “formatted_address” a partir de las coordenadas (lat, lng) me devuelve un blank, es como si no devolviera nada la promesa en results.

    Espero que me pueda ayudar, igualmente gracias por la excelente aportación!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.