Tutorial de Ionic – Crear una aplicación para guardar nuestros sitios geolocalizados – Parte 3: Añadiendo FAB, marcador y ventana modal.

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 insertar en nuestra app un mapa de google maps centrado en las coordenadas actuales.
Vamos a continuar desarrollando nuestra app.

Para poder apreciar mejor donde estamos situados vamos a mostrar un marcador personalizado en el mapa que nos indique nuestra posición.

Para el marcador vamos a utilizar una imagen personalizada. La forma correcta de utilizar imágenes locales en nuestra app es alojarlas en la carpeta src/assets, así que vamos a crear dentro de src/assets una carpeta la la que llamaremos img donde alojaremos nuestras imágenes.

Podemos poner la imagen que queramos como  marcador para el mapa. Si no os queréis complicar podéis dar botón derecho sobre la siguiente imagen y descargarla para utilizarla en este ejemplo:

Bien, una vez descargada la imagen la copiamos en la carpeta img que acabamos de crear.

Ahora para situar el marcador en el mapa editamos el archivo inicio.ts y en la función loadMap() que muestra el mapa añadimos el siguiente código:

loadMap(){

   let mapContainer = document.getElementById('map');
    this.map = new google.maps.Map(mapContainer, {
      center: this.coords,
      zoom: 12
    });
    
    // Colocamos el marcador
    let miMarker = new google.maps.Marker({
              icon : 'assets/img/ico_estoy_aqui.png',
              map: this.map,
              position: this.coords
          });

}

No hay mucho que comentar, como veis para crear un marcador creamos un objeto google.maps.Marker  y le pasamos un objeto como parámetro donde en icon le indicamos donde se aloja la imagen del icono, en este caso la ruta a la imagen que hemos guardado destro de assets en la carpeta img es ‘assets/img/ico_estoy_aqui.png’, si vuestra imagen se llama de otra forma tenéis lógicamente que poner el nombre de la imagen que vayáis a utilizar.
En map le idicamos la variable que contiene el mapa donde se tiene que situar, es este caso this.map, por ultimo en position le asignamos las coordenadas donde se tiene que situar, en este caso le pasamos la variable this.coords que contiene las coordenadas actuales.

Ahora si ejecutamos ionic serve -l veremos en el navegador algo como esto:

Mostrando un marcador en el mapa
Mostrando un marcador en el mapa

Ahora vamos a dar un paso más y vamos a añadir un FAB (Floating Action Button) es decir botón de acción flotante al mapa.Los FAB son componentes estándar de material design, tienen la forma de un círculo y flotan sobre el contenido en una posición fija.

Este FAB lo utilizaremos para añadir la posición actual a nuestros sitios, para ello haremos que cuando se pulse en el fav se habra una ventana modal donde mostraremos un pequeño formulario donde aparecerán las coordenadas y la dirección de la posición actual y nos permitirá añadir una descripción y una fotografía desde la cámara de nuestro móvil.

Vayamos por partes.

Primero vamos a colocar el FAB en la vista de muestra página de inicio, editamos el archivo inicio.html y añadimos lo que esta marcado con fondo amarillo.

<!--
  Generated template for the Inicio page.

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

  <ion-navbar>
    <ion-title>Inicio</ion-title>
  </ion-navbar>

</ion-header>

<ion-content padding>
  <div id="map"></div>
   <ion-fab right top>
    <button ion-fab (tap)="nuevoSitio()">
      <ion-icon name="pin"></ion-icon>
      <ion-icon name="add"></ion-icon>
    </button>
  </ion-fab>
  </ion-content>

Bien, como vemos tenemos el componente ion-fab al que le indicamos que se sitúe arriba a la derecha con right top.

En su interior contiene un botón al que le tenemos que indicar que es del tipo ion-fab.

Con (tap)=”nuevoSitio()” le indicamos que cuando se pulse o tape el botón se llame a la función nuevoSitio() que definiremos luego en el controlador de la página.

Después tenemos dos componentes ion-icon para mostrar los iconos en el FAB, uno con el icono pin y otro con el icono add, lo habitual es mostrar un solo icono, pero he querido poner dos para que quede más claro que queremos añadir una localización.

Si probamos ahora nuestra app tendrá un aspecto similar a este:

Bien, ahora vamos a definir la función nuevoSitio() en el controlador, editamos el archivo inicio.ts y añadimos la siguiente función debajo de la función loadMap:

nuevoSitio(){
 // aquí vamos a abrir el modal para añadir nuestro sitio.
}

La idea es que al llamar a esta función desde el FAB se abra un modal para poder añadir una descripción y una foto a muestro sitio si lo deseamos, vamos a explicar un poco que son los modales y como se utilizan:

Modales

Los modales son como ventanas que se abren dentro de nuestra aplicación sin que afecten a la pila de navegación.

Para crear un modal debemos de crear una página con el ionic generator.
Desde consola vamos a escribir el siguiente comando para crear el modal donde irá el formulario para introducir el nuevo sitio:

ionic g page modalNuevoSitio

Ahora en inicio.ts debemos importar el componente ModalController  de la librería ionic-angular, por lo tanto después de NavController y NavParams importamos también ModalController.

import { NavController, NavParams, ModalController } from 'ionic-angular';

Debemos inyectar también en el constructor el componente ModalController al que hemos llamado modalCtrl:

constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    private geolocation: Geolocation,
    public modalCtrl : ModalController,
    platform: Platform) {

    ......

Ahora ya estamos listos para crear el modal en nuestra función nuevoSitio.

Para crear un modal utilizamos el método create del componente ModalController y le pasamos como primer parámetro un string con el nombre del  controlador de la página que hemos creado para el modal llamado ModalNuevoSitioPage.
El segundo parámetro es opcional y se utiliza para pasarle datos a nuestro modal, en este caso lo vamos a utilizar para pasarle el objeto this.coords que contiene las coordenadas que hemos obtenido.

Una vez creado el modal para que se muestre en pantalla invocamos al método present();

nuevoSitio(){
  // aquí vamos a abrir el modal para añadir nuestro sitio.
   let mimodal = this.modalCtrl.create( 'ModalNuevoSitioPage',this.coords );
   mimodal.present();
}

Ahora que sabemos como mostrar un modal y como pasarle datos desde la página que lo llama, vamos a ver como recibimos esos datos y los mostramos en el modal.

Recordad que al usar lazy loading y declarar la página del modal en su propio modulo (inicio.module.ts) no debemos declararlo en app.module.ts.

Vamos a crear una variable  en el controlador del modal (modal-nuevo-sitio.ts) que al igual que en la página inicio llamaremos coords y sera de tipo any, esta variable al igual que en la página de inicio va a contener un objeto con la latitud y longitud que recibimos en la llamada.

Para recibir los datos desde la página que llama al modal solo tenemos que utilizar el método get de NavParams que ya se importa por defecto al crear una página. Con navParams controlamos los parámetros que recibimos.
Dentro de la función ionViewDidLoad que se ejecuta al cargar la vista vamos a asignar a cada atributo del objeto coords  que acabamos de crear el valor que corresponde de la latitud y longitud que recibimos.
Veamos como tiene que quedar el código de modal-nuevo-sitio.ts en estos momentos:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';


/*
  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 }

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

  ionViewDidLoad() {
    console.log('ionViewDidLoad ModalNuevoSitioPage');
    this.coords.lat = this.navParams.get('lat');
    this.coords.lng = this.navParams.get('lng');
  }
}

Ahora que hemos recibido las coordenadas desde la página inicio vamos a mostrarlas en el modal para comprobar que las recibimos correctamente, para ello vamos a editar el archivo modal-nuevo-sitio.html y simplemente añadimos las coordenadas dentro de ion-content:

<ion-content padding>
  <p>Hemos recibido: {{ coords.lat }}, {{ coords.lng }}<p>
</ion-content>

Si probamos ahora muestra aplicación observamos que al pulsar el botón (FAB) que hemos creado para añadir sitios nos abre una ventana modal donde se muestran las coordenadas que acabamos de recibir, pero tenemos un pequeño problema, y es que no tenemos forma de cerrar el modal, así que antes de editar cualquier otra cosa en la página vamos a crear un botón de cerrar.

Para cerrar el modal tenemos que importar en el controlador de la pagina del modal (modal-nuevo-sitio.ts) el controlador ViewController e inyectarlo en el constructor.

Luego creamos una función que vamos a llamar cerrarModal donde utilizaremos  el método dismiss de ViewController para cerrarlo:

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


/*
  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 }
  constructor(public navCtrl: NavController, public navParams: NavParams, private viewCtrl : ViewController ) {}

  ionViewDidLoad() {
    console.log('ionViewDidLoad ModalNuevoSitioPage');
    this.coords.lat = this.navParams.get('lat');
    this.coords.lng = this.navParams.get('lng');
  }

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

}

Ahora vamos a añadir el botón de cerrar que llamará a la función cerrarModal que acabamos de crear  en la cabecera de la vista de la página del modal (modal-nuevo-sitio.html), aprovechamos tambien para cambiar el título del modal a “Nuevo sitio”:

<!--
  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>
  <p>Hemos recibido: {{ coords.lat }}, {{ coords.lng }}<p>
</ion-content>

Ahora ya tenemos un botón de cerrar para nuestro modal, si habéis seguido correctamente todos los pasos al pulsar sobre el FAV se abrirá nuestro modal como en la siguiente imagen:

Por ahora lo dejamos aquí, hoy hemos aprendido como añadir un marcador al mapa de Google maps, como añadir a nuestra app botones tipo FAB, y como crear, abrir, pasar datos y cerrar un modal.
En el próximo post veremos como añadir un nuevo  con descripción y foto, haciendo uso de la cámara del móvil.

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.

30 comentarios en “Tutorial de Ionic – Crear una aplicación para guardar nuestros sitios geolocalizados – Parte 3: Añadiendo FAB, marcador y ventana modal.

  1. Por cierto!, se me olvido acotar lo siguiente.
    Dentro de tu código, en la función ionViewDidLoad(), las variables para obtener las coordenadas, están sin cerrar el paréntesis y sin el punto y coma. Puede que eso le cause problemas a alguien. Saludos!

    1. También acotar, que al final, en el ultimo paste del código, dentro del ion-content padding, hay que incluir las coordenadas recibidas por el controlador, tal cual se muestra un poco más arriba en el tutorial

    2. Hola Dc, estoy revisando el código pero yo veo que está todo cerrado, es decir en la función ionViewDidLoad el código es este:
      ionViewDidLoad() {
      console.log(‘ionViewDidLoad ModalNuevoSitioPage’);
      this.coords.lat = this.navParams.get(‘lat’);
      this.coords.lng = this.navParams.get(‘lng’);
      }

      ¿Puede ser que no se visualice correctamente en el navegador que estás utilizando?

      En cualquier caso gracias por comentar.

      1. Edu, es el pa parte del código en donde nos enseñas a crear la función cerrarModal(), si te fijas arriba de ella esta la función para obtener las coordenadas, y no esta el paréntesis. Slds

  2. Gracias Dc, me pasaba una cosa muy extraña y es que cuando estaba logeado con mi usuario que es administrador lo veía correctamente por eso no encontraba el fallo sin embargo si entraba sin logearme si que he visto el fallo.
    Muchas gracias por avisarme 🙂

  3. Vaya, vuelvo a ser yo quien nada más empezar se encuentra con un error, lo siento.
    Mira Edu, al insertar estas líneas:

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

    … no me aparece el mapa y desde consola me lanza el siguiente error:

    [23:51:45] dev server running: http://localhost:8100/

    [23:51:52] tslint: C:/WWW/NPM/misSitios/src/pages/inicio/inicio.ts, line: 66
    Unused variable: ‘miMarker’

    L65: // Colocamos el marcador
    L66: let miMarker = new google.maps.Marker({
    L67: icon : ‘assets/img/ico_estoy_aqui.png’,

    [23:51:53] lint finished in 8.42 s

    A ver si podéis echarme un cable.

    1. Hola Luis, el error que te sale es solo una advertencia de que la variable miMarker no la estamos utilizando, para que desaparezca puedes quitar let miMarker y dejar solo la llamada a la creación del objeto:
      new google.maps.Marker({
      icon : ‘assets/img/ico_estoy_aqui.png’,
      map: this.map,
      position: this.coords
      });

      Sin embargo puede ser interesante tener el marcador en una variable si más adelante por ejemplo quieres que al pulsar sobre el marcador muestre la dirección o realizar alguna otra acción con el marcador. No tiene mayor importancia ese aviso.
      No tiene que ver con el hecho de que no se muestre el mapa.
      Revisa el código de todos los archivos que hemos modificado en esté tutorial por si tienes algo mal escrito o te falta alguna cosa, también tienes que tener en cuenta que tienes que tener conexión a internet en el momento de hacer las pruebas (doy por hecho que sí) y puede que tarde un poco en salir el mapa, aunque si tienes una conexión “normal” no suele tardar mas de unos segundos.

      Un saludo

      1. Tal cual Edu, hoy que vuelvo al trabajo he sacado unos minutos para revisar la aplicación y he detectado que me faltaba declarar la capa donde se pintaba el mapa:

        Saludos!

  4. Hola Edu.
    He actualizado todo Ionic2… y hoy he querido hacer otra aplicación utilizando los modals…
    pero sin importar lo que haga, luego de crear la pagina con el CLI e importarla en el app.module.ts me tira error…
    Cannot find module :/
    Podrias hecharme una mano?
    ha cambiado algo con la actualización del CLI?

    1. Ahora al ejecutar ionic g page en vez de crear 3 archivos, crea 4… donde uno termina nombre.module.ts
      Y este es el que me esta causando problemas al parecer… con la funcion
      forChild

      import { NgModule } from ‘@angular/core’;
      import { IonicModule } from ‘ionic-angular’;

      import { ModalNuevoSitioPage } from ‘../pages/modal-nuevo-sitio/modal-nuevo-sitio’;

      @NgModule({
      declarations: [
      ModalNuevoSitioPage,
      ],
      imports: [
      IonicModule.forChild(ModalNuevoSitioPage),
      ],
      exports: [
      ModalNuevoSitioPage
      ]
      })
      export class ModalNuevoSitioModule {}

        1. Hola Dc, muchísimas gracias por el aporte.

          Es cierto que acaba se salir ionic3 y trae algunos cambios. No son cambios radicales como lo fué el salto de ionic 1 a ionic 2, pero si que hay que tener en cuanta algunas cosas.
          Sin duda habra que tener en cuanta esta nueva versión y puede que tenga que cambiar o por lo menos comentar algunas cosas en los posts anteriores.
          Muchas gracias por valiosa información.

          Un saludo

  5. Hola Eduardo! Tengo una duda,
    Me pasa que si esta desactivado el gps, el mapa no se muestra obviamente, pero si esta desactivado ya dentro de la aplicacion, y luego lo activo, al entrar a mi componente donde tengo el mapa, no se muestra el mapa, sabes que puedo hacer en este caso?

    1. Hola Meggie, puede probar a llamar a obtenerPosicion() dentro del evento ionViewDidEnter que se ejecuta cuando la página ha sido cargada y ahora es la página activa, tendrías que añadir la siguiente función al controlador:

      ionViewDidEnter() {
      this.obtenerPosicion();
      }

      Un saludo

  6. Hola eduardo, disculpa tengo un error al momento de abril el modal, me da el error
    “Runtime Error
    Uncaught (in promise): invalid link: ModalNuevoSitioPage”

    eh estado haciendo tal cual lo realizas tu, no se si se deba a que ya no genera las 4 paginas ionic.

    espero puedas ayudarme, saludos

    1. Hola ternoise, este error se debe a que el la versión 3.5.2 de ionic se ha desactivado la creación automática del archivo .module.ts al crear una nueva página con ionic g. He modificado el tutorial para incluir la creación a mano de este archivo.

      Un saludo

  7. Hola eduardo, disculpa tengo un error al momento de abril el modal, me da el error
    “Runtime Error
    Uncaught (in promise): invalid link: ModalNuevoSitioPage”

    eh estado haciendo tal cual lo realizas tu, no se si se deba a que ya no genera las 4 paginas ionic.

    espero puedas ayudarme, saludos

    1. Hola gamster 12, este error se debe a que el la versión 3.5.2 de ionic se ha desactivado la creación automática del archivo .module.ts al crear una nueva página con ionic g. He modificado el tutorial para incluir la creación a mano de este archivo.

      Un saludo

  8. gracias por contestarme la ultima vez, al querer mostrar las coordenadas en el modal simplemente no las muestra.. no marca error ni nada sabes a que se pueda deber?

  9. Hola Eduardo,

    Primero de todo muchas gracias por el tutorial, me ocurre el mismo error que a los comentarios anteriores:
    “Runtime Error
    Uncaught (in promise): invalid link: ModalNuevoSitioPage”

    En tus comentarios pones que has modificado el tutorial para la creación a mano pero no lo veo…

    Gracias

    1. Hola David, eso ocurría en la versión 3.5.2 que se dejarón de crear automáticamente los archivos .module.ts, pero en la siguiente versión volvieron a generarse automáticamente.
      Acabo de probar con la versión que tengo instalada actualmente 3.13.2 y funciona correctamente.
      ¿Que versión tienes instalada?, ¿No te ha generado el archivo modal-nuevo-sitio.module.ts?

      Un saludo

Responder a Eduardo Revilla Cancelar la 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.