Componentes (Parte 1)

<< Crear un proyecto Componentes (Parte 2) >>

En esta sección vamos a ver componentes de Ionic que prácticamente no necesitan código para crearlos o interactuar con ellos. Es decir, trabajaremos principalmente a nivel de diseño (HTML).

Utilidades CSS

Ionic proporciona algunos atributos para propiedades CSS genéricas, como alineación de texto, relleno, margen o un sistema de rejilla. Puedes ver ejemplos de estas propiedades en la documentación oficial de Utilidades CSS.

Sistema de rejilla

Ionic cuenta con un sistema de rejilla sencillo basado en Flexbox. Podemos dividir contenido en columnas si es necesario. Para hacer esto, creamos elementos de fila (ion-row) y columnas (ion-col) dentro de ellas. Podemos colocar filas dentro de un elemento ion-grid para tener un espacio adicional entre las filas.

La rejilla se divide en 12 columnas (similar a Bootstrap). Por defecto, todas las columnas ocupan el mismo espacio. Podemos utilizar atributos como size="auto" (una columna solo ocupa el espacio mínimo necesario), size="1" (1, 2, 3, 4, ..., 12 → número de columnas que ocupa), offset="1" (número de columnas desplazadas hacia la derecha), etc. Casi todos los atributos tienen equivalentes para pantallas pequeñas, medianas, grandes, etc. (size-sm, size-md, offset-lg, etc.).

<!-- ... -->
<ion-grid>
  <ion-row>
    <ion-col size-lg="3">
      <p>This content takes 50% of space (default) and 25% in large screens</p>
      <ion-button expand="block" color="primary">A button</ion-button>
    </ion-col>
    <ion-col size-lg="9">
      <p>This content also takes 50% of space, and 75% in large screens</p>
      <ion-button expand="block" color="secondary">Other button</ion-button>
    </ion-col>
  </ion-row>
  <ion-row>
    <ion-col size="6" offset="3">
      This content has 25% margin from the left side and takes 50% of space.
    </ion-col>
  </ion-row>
</ion-grid>
<!-- ... -->

Botones

Los botones pueden tener varios estilos, como se muestra en la documentación. Un botón en Ionic se crea con el componente ion-button.

Un botón, al igual que muchos componentes en Ionic, puede tener un color (usando el parámetro color). El valor del color debe estar definido en src/theme/variables.scss ($colors).

<!-- ... -->
<ion-button color="light">Light</ion-button>
<ion-button>Default</ion-button>
<ion-button color="secondary">Secondary</ion-button>
<ion-button color="danger">Danger</ion-button>
<ion-button color="dark">Dark</ion-button>
<!-- ... -->

Otros parámetros útiles son:

  • fill → "solid": botón relleno con el color especificado, "clear": fondo transparente y text del color especificado, "outline": igual que clear pero con borde de color.
  • size → Tamaño del botón: "default" (por defecto), "small", "large"
  • expand → "block": ocupa todo el ancho disponible con algo de margen, "full": igual que block pero sin dejar márgenes a los lados.

Iconos

Para colocar un ícono dentro de un elemento de lista, botón, etc., utilizamos el componente <ion-icon>. Este elemento tiene un atributo llamado "name" donde indicamos qué ícono queremos mostrar. Puedes ver la lista completa de íconos de Ionic. El atributo "slot" ("start", "end", "icon-only") indica dónde alinear el ícono dentro de un elemento de lista, botón, etc.

<!-- ... -->
<ion-button>
  <ion-icon slot="start" name="star"></ion-icon>
  Left Icon
</ion-button>

<ion-button>
  Right Icon
  <ion-icon slot="end" name="star"></ion-icon>
</ion-button>

<ion-button>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>
<!-- ... -->

Para poder usar los iconos, debemos importar primero en AppComponent los iconos que vamos a utilizar en nuestra aplicación y registrarlos en la función addIcons.

Listas

Podemos crear una lista de elementos con el componente <ion-list>. Estas listas contendrán elementos de tipo <ion-item>. Esas listas pueden tener elementos simples (una sola línea de texto) o elementos complejos (imagen, múltiples líneas, botones deslizantes, ...). Puedes consultar la documentación oficial de ion-list e ion-item.

Los elementos que podemos poner dentro de las listas son:

  • ion-item → Representa a un elemento de la lista. Puede ser un elemento simple con texto o puede contener a su vez varios tipos de elementos como ion-label, ion-input, ion-avatar, ion-button, ion-radio, ion-note, ...
  • ion-list-header → Representa el encabezado de la lista. Solo puede haber uno (o ninguno) y tiene que estar al principio de la lista.
  • ion-item-group → Sirve para agrupar varios elementos de la lista en un grupo. Estos grupos pueden tener su propio encabezado utilizando el elemento ion-item-divider
  • ion-item-sliding → Permite crear elementos de lista deslizantes con una serie de botones que podemos colocar a izquierda y derecha para añadir acciones a dicho elemento. Para ello contiene un elemento ion-item y uno o dos elementos ion-item-sliding → Permite crear elementos de lista deslizantes con una serie de botones que podemos colocar a izquierda y derecha para añadir acciones a dicho elemento. Para ello contiene un elemento ion-item y uno o dos elementos ion-item-options

Los elementos de lista (ion-item) pueden comportarse como botones, con animación de click, añadiendo el atributo button o un enlace con routerLink, por ejemplo.

<!-- ... -->
<ion-list>
  <ion-list-header color="secondary"> People </ion-list-header>
  <ion-item>
    <ion-avatar slot="start">
      <img src="./assets/tiofeo.jpg" />
    </ion-avatar>
    <ion-label>
      <h2>Ugly man</h2>
      <h3>I'm a big deal</h3>
      <p>Listen, I've had a pretty messed up day...</p>
    </ion-label>
  </ion-item>
  <ion-item>
    <ion-avatar slot="start">
      <img src="./assets/tioraro.jpg" />
    </ion-avatar>
    <ion-label>
      <h2>Weird man</h2>
      <h3>I don't know who am I</h3>
      <p>More text...</p>
    </ion-label>
  </ion-item>
</ion-list>
<!-- ... -->

Inputs

Los elementos más utilizados en formularios son <input> y . Ionic utiliza los elementos ion-input e ion-textarea en su lugar. Ambos elementos se pueden vincular a un atributo del componente con la directiva ngModel (formularios de plantilla) o formControlName (formularios reactivos). Además, los campos de formulario de una aplicación Ionic suelen estar dentro de un elemento ion-item (a su vez dentro de ion-list).

Algunos de los parámetros que podemos configurar son:

  • label → Texto que acompaña al campo para informar al usuario de lo que debe introducir. En versiones anteriores de Ionic había que utilizar un elemento ion-label para ello.
  • labelPlacement → Posición donde se sitúa el texto del parámetro label. Puede tener los valores default (izquierda), fixed(izquierda con más margen), stacked (arriba en pequeño) o floating (dentro del campo cuando está vacío y arriba con contenido)
  • placeholder → Texto auxiliar que solo aparece dentro del campo cuando este está vacío. Sirve para añadir más información sobre lo que hay que introducir. Su presencia puede hacer innecesario el uso de label.
  • clearInput → Valor booleano (por defecto false). Si lo ponemos a true, añade un pequeño botón a la derecha para borrar el contenido del campo.
  • helperText → Texto de ayuda que aparece debajo del campo en pequeño. Se puede añadir más información. Aparece siempre que el valor del campo sea válido o no haya sido visitado aún.
  • errorText → Texto de error que aparece abajo en rojo cuando el campo ha sido visitado y su contenido no es válido.
  • counter → Cuando se añade la propiedad maxlength en un campo y el parámetro [counter]="true", aparece un texto abajo a la derecha indicando cuantos caracteres quedan para que se llene el campo.
  • color → Cuando el campo tiene el foco, podemos cambiar el color en el que se resalta el campo (por defecto primary).
  • autogrow → Este parámetro admite un booleano (por defecto false) y solo es aplicable a ion-textarea. El campo crece verticalmente conforme añadimos líneas, por lo que no hay que hacer scroll.

Los campos de tipo email (type="email") deben contener el atributo email para que se validen como tales. Además, los campos que tengan un texto de ayuda, de error, o un contador de caracteres añaden una línea de separación debajo del campo. Es recomendable por cuestión de diseño quitarle el borde inferior al elemento ion-item en ese caso con el atributo lines="none".

<!-- ... -->
<form>
  <ion-list>
    <ion-item lines="none">
      <ion-input label="Name" labelPlacement="floating" placeholder="Enter name"
        errorText="Name is required" required [counter]="true" name="name"
        [(ngModel)]="data.name"
      ></ion-input>
    </ion-item>
    <ion-item lines="none">
      <ion-input type="email" label="Email" labelPlacement="floating" placeholder="Enter email"
        errorText="Enter a valid email" required email name="email" [(ngModel)]="data.email"
      ></ion-input>
    </ion-item>
    <ion-item lines="none">
      <ion-textarea label="Description" labelPlacement="floating" placeholder="Tell me something about you"
        errorText="Description is required" maxlength="120" required [counter]="true" [autoGrow]="true"
        name="description" [(ngModel)]="data.description"
      ></ion-textarea>
    </ion-item>
    <!-- ... -->
  </ion-list>
</form>
<!-- ... -->

También se pueden integrar iconos o botones a ambos lados del input utilizando proyección de contenido o slots. Para ello metemos el icono o botón dentro del elemento ion-input y le indicamos si queremos que lo ponga a la derecha (slot="start"), o izquierda (slot="end").

<!-- ... -->
<ion-item lines="none">
  <ion-input [type]="showPass ? 'text' : 'password'" label="Password" labelPlacement="floating" 
    placeholder="Enter password" errorText="Password required and min 4 characters"
    required minlength="4" name="password" [(ngModel)]="data.password"
  >
    <ion-icon slot="start"  [name]="showPass ? 'lock-open' : 'lock-closed'" aria-hidden="true"></ion-icon>
    <ion-button fill="clear" slot="end" aria-label="Show/hide" (click)="showPass = !showPass">
      <ion-icon slot="icon-only" [name]="showPass ? 'eye' : 'eye-off'" aria-hidden="true"></ion-icon>
    </ion-button>
  </ion-input>
</ion-item>
<!-- ... -->

Datetime

El componente ion-datetime de Ionic integra su propio selector de fecha y hora para seleccionar y mostrar fácilmente la fecha, la hora o ambas. Funciona de manera similar al elemento HTML <input type="datetime-local" />.

Además, podemos utilizar la directiva [(ngModel)] para vincular este control a un valor. Este valor no es un objeto Date, sino que debe ser una cadena que represente una fecha en el formato ISO 8601 (por ejemplo, 1994-12-15T13:47 o 1994-12-15T13:47:20.789+5:00). Este formato suele ser utilizado por los sistemas de bases de datos.

Algunos de los parámetros que admite este elemento son:

  • min y max → Se puede establecer una fecha mínima y máxima para seleccionar. El formato debe ser el mencionado anteriormente (ejemplo: min="1990-01-01").
  • locale → Establece el idioma de los días, meses, etc.
  • firstDayOfWeek → Establece el primer día de la semana (por defecto domingo: 0). Si queremos que sea lunes tendríamos que poner [firstDayOfWeek]="1".
  • presentation → Formato del calendario. Puede tomar valores como 'date' (solo fecha), 'date-time' (fecha y hora), 'time-date' (hora primero y fecha), 'time' (solo hora).
  • preferWheel → Recibe un valor booleano (por defecto false). Si lo establecemos a true, utiliza un formato de rueda para seleccionar la fecha en lugar de un calendario.
<!-- ... -->
<ion-item>
  <ion-label>Birth date: {{data.birth | date:'dd/MM/yyyy'}}</ion-label>
  <ion-datetime locale="es-ES" presentation="date" [firstDayOfWeek]="1"
    [preferWheel]="true" name="birth" required [(ngModel)]="data.birth"
  ></ion-datetime>
</ion-item>
<!-- ... -->

Si queremos mostrar el selector de fecha en una ventana modal podemos utilizar el elemento ion-datetime-button.

Checkbox

El componente ion-checkbox de Ionic funciona de la misma manera que el elemento HTML <input type="checkbox" />, pero este componente se adapta al estilo de cada plataforma y puede tener colores diferentes (atributo color). El texto que acompaña al elemento se pone dentro del mismo.

<!-- ... -->
<ion-item>
  <ion-checkbox color="success" [(ngModel)]="data.discount" name="discount">
    I want a discount
  </ion-checkbox>
</ion-item>
<!-- ... -->

Si queremos, por ejemplo, que el checkbox aparezca a la izquierda en lugar de a la derecha (por defecto), podemos utilizar el atributo labelPlacement con el valor end.

<!-- ... -->
<ion-item>
  <ion-checkbox color="success" slot="start" [(ngModel)]="data.discount"
    name="discount" labelPlacement="end"
  >I want a discount</ion-checkbox>
</ion-item>
<!-- ... -->

Radio

Los botones de opción se presentan en Ionic como un grupo de elementos donde solo puedes elegir uno de ellos. Estos elementos (ion-radio) deben colocarse dentro de un elemento ion-radio-group (la directiva [(ngModel)] debe ubicarse aquí). Las forma de usarlo y opciones son muy similares al elemento ion-checkbox.

<!-- ... -->
<ion-radio-group [(ngModel)]="data.food" name="food" value="pizza">
  <ion-item-divider>
    <ion-label>Favourite food</ion-label>
  </ion-item-divider>
  <ion-item>
    <ion-radio color="secondary" value="pizza">Pizza</ion-radio>
  </ion-item>
  <ion-item>
    <ion-radio color="danger" value="hamburguer">Hamburguer</ion-radio>
  </ion-item>
  <ion-item>
    <ion-radio color="success" value="salad">Salad</ion-radio>
  </ion-item>
</ion-radio-group>
<!-- ... -->

Toggle

El componente ion-toggle tiene el mismo funcionamiento que ion-checkbox, con la diferencia del aspecto gráfico. En este caso se presenta como un interruptor que puede estar encendido o apagado. También tienen la propiedad enableOnOffLabels que si la habilitamos (true), aparecerá un icono extra de encendido y apagado en el interruptor que hará más fácil distinguir cuando se habilita o deshabilita.

<!-- ... -->
<ion-item>
  <ion-toggle color="danger" [enableOnOffLabels]="true"
    [(ngModel)]="data.premium" name="premium"
  >
    Premium (10€ month)
  </ion-toggle>
</ion-item>
<!-- ... -->

Range

El componente ion-range es una buena opción cuando tenemos que elegir un número dentro de un rango determinado. Es decir, se comporta como un input de tipo number con valor mínimo y máximo (pero con otro estilo visual, claro).

Este componente admite varias opciones o parámetros:

  • label → Etiqueta asociada al campo. Puede cambiarse su posición con el parámetro labelPlacement, como en un elemento ion-input.
  • pin → Si establecemos esta propiedad booleana a true, mostrará una burbuja con el valor cuando movamos el botón.
  • min y max → Establece el valor mínimo y máximo que podemos seleccionar. Por defecto el mínimo es 0 y el máximo 100.
  • dualKnobs → Habilita la opción de seleccionar un rango. Es decir un valor inferior y otro superior. En este caso, en lugar de guardar un número, se almacenará un objeto con las propiedades lower y upper.
  • snaps y ticks → Habilita la opción de seleccionar un rango. Es decir un valor inferior y otro superior.

Se pueden añadir, además, iconos o texto (ion-note) a los lados del elemento, metiéndolos dentro y con la opción slot ponerlos a izquierda (start) o derecha (end)

<!-- ... -->
<ion-item>
  <ion-range label="Skill level" min="0" max="100" step="5"
    [snaps]="true" [ticks]="true" [pin]="true"
    color="primary" [(ngModel)]="data.skill" name="skill"
  >
  <ion-note slot="start">0</ion-note>
  <ion-note slot="end">100</ion-note>
  </ion-range>
</ion-item>
<ion-item>
  <ion-range label="Lessons week" min="3" max="20" [pin]="true"
    [dualKnobs]="true" color="success" [(ngModel)]="data.lessons"
    name="lessons"
  >
  <ion-icon slot="start" color="medium" name="remove"></ion-icon>
  <ion-icon slot="end" color="medium" name="reorder-four"></ion-icon>
  </ion-range>
</ion-item>
<!-- ... -->

Select

El componente ion-select de Ionic es el equvalente a una lista de selección (<select>). La principal diferencia es que debemos utilizar los elementos ion-select e ion-select-option. Cuando haces clic en el elemento, aparecerá un cuadro de diálogo para seleccionar una opción.

Algunas opciones que podemos añadir son:

  • label → Etiqueta asociada al campo. Puede cambiarse su posición con el parámetro labelPlacement, como en un elemento ion-input.
  • okText y cancelText → Permiten establecer el texto del botón de confirmar y cancelar del cuadro modal.
  • multiple → Si lo establecemos a true, se permitirá la selección de múltiples opciones. Devuelve los elementos seleccionados en un array.
<!-- ... -->
<ion-item>
  <ion-select label="Favourite seasons" [multiple]="true"
    [(ngModel)]="data.season" name="season"
  >
    <ion-select-option value="winter">Winter</ion-select-option>
    <ion-select-option value="spring">Spring</ion-select-option>
    <ion-select-option value="summer">Summer</ion-select-option>
    <ion-select-option value="autumn">Autumn</ion-select-option>
  </ion-select>
</ion-item>
<!-- ... -->

Cards

Las cards (ion-card) se utilizan para presentar contenido importante en un patrón de diseño que se está volviendo cada vez más común cada día. Se pueden ver como un componente más complejo que ion-item (puedes poner casi cualquier cosa dentro de una cards, como una lista, por ejemplo).

Puedes ver las posibilidades que tienen las cards en la documentación oficial de Ionic. Dentro de una card, puedes colocar:

  • ion-card-header → Encabezado de la card (elemento superior, opcional). Suele contener elementos a su vez como ion-card-title y ion-card-subtitle
  • ion-card-content → Contenido principal de la card. Añade padding.
  • Podemos poner una imagen (img, ion-img) al principio de la card
  • También podemos añadir botones (ion-button), ion-item, etc dentro o fuera de ion-card-content. Si los situamos fuera, no tendrán padding alrededor.
  • También se puede utilizar la propiedad color en el elemento ion-card para el color de fondo de la misma.
<!-- ... -->
<ion-card>
  <img src="./assets/mapa.jpg" alt="" style="width: 100%;" />
  <ion-item>
    <ion-icon name="pin" slot="start"></ion-icon>
    <ion-label>Show map</ion-label>
    <ion-button fill="outline" slot="end">Show</ion-button>
  </ion-item>
  <ion-card-header>
    <ion-card-subtitle>Destination</ion-card-subtitle>
    <ion-card-title>Harderwijkweg</ion-card-title>
  </ion-card-header>
  <ion-card-content>
    Founded in 1829 on an isthmus between Lake Monona and Lake Mendota, Madison was named the capital of the Wisconsin Territory in 1836.
  </ion-card-content>
</ion-card>
<!-- ... -->

Badges

El componente ion-badge se utiliza para destacar un valor, normalmente numérico que se incluye como parte de un texto a mostrar, o como elemento de información extra dentro de ion-item, por ejemplo, para indicar cosas como notificaciones pendientes, cantidades disponibles, o similar. Se puede configurar su color, y su posición (slot) dentro de un elemento ion-item o similar.

<!-- ... -->
<div>
  <ion-badge color="secondary">10</ion-badge>
  <ion-badge color="primary">20</ion-badge>
  <ion-badge color="dark">30</ion-badge>
  <ion-badge color="danger">40</ion-badge>
</div>

<ion-item>
  <ion-badge slot="end" color="danger">23</ion-badge>
  <ion-label>Friends</ion-label>
</ion-item>
<!-- ... -->

Chips

El componente ion-chip se puede interpretar como una versión algo más compleja de un ion-badge. Además de texto, puede contener iconos o imágenes de avatar (ion-avatar). Puede usarse para representar etiquetas, contactos, etc.

<!-- ... -->
<ion-chip color="dark">
  <ion-label>Chip with Icon</ion-label>
  <ion-icon name="close-circle" color="danger"> </ion-icon>
</ion-chip>
<!-- ... -->

Fabs

Los Fabs (ion-fab-button) son botones flotantes colocados dentro de un contenedor ion-fab. Los contenedores de botones se pueden alinear en una posición absoluta utilizando atributos verticales (top, bottom, center), horizontales (start, end, center) y de borde. También pueden contener listas de botones (ion-fab-list) que aparecen cuando hacemos clic en el botón principal.

También tienen la propiedad edge, que es un booleano que cuando el botón está arriba, lo sitúa entre el elemento ion-header e ion-content, en lugar de ponerlo dentro de ion-content. Lo mismo cuando el botón está abajo y hay un ion-footer presente.

<!-- ... -->
<ion-fab vertical="bottom" horizontal="start" slot="fixed">
  <ion-fab-button>
    <ion-icon name="share"></ion-icon>
  </ion-fab-button>
  <ion-fab-list side="end">
    <ion-fab-button>
      <ion-icon name="logo-facebook" color="tertiary"></ion-icon>
    </ion-fab-button>
    <ion-fab-button>
      <ion-icon name="logo-instagram" color="danger"></ion-icon>
    </ion-fab-button>
    <ion-fab-button>
      <ion-icon name="logo-twitter" color="primary"></ion-icon>
    </ion-fab-button>
  </ion-fab-list>
  <ion-fab-list side="top">
    <ion-fab-button>
      <ion-icon name="logo-vimeo" color="secondary"></ion-icon>
    </ion-fab-button>
    <ion-fab-button>
      <ion-icon name="logo-youtube" color="danger"></ion-icon>
    </ion-fab-button>
  </ion-fab-list>
</ion-fab>
<!-- ... -->

Toolbar

Las barras de herramientas ion-toolbar son componentes que ocupan todo el espacio horizontal y se utilizan para colocar títulos, botones, campos de texto, etc. Puede haber más de una en la misma página y se pueden colocar dentro de un ion-header, ion-footer o ion-content (en este caso, se desplaza con el contenido).

Los botones deben colocarse dentro de un elemento ion-buttons. Estos grupos de botones pueden posicionarse con el atributo slot y estos valores:

  • start → Se coloca la izquierda.
  • end → Se coloca a la derecha.
  • primary → Se coloca a la derecha.
  • secondary → En iOS se coloca a la izquierda, mientras que en Android se coloca a la derecha (pero antes de los botones primary).

Scroll Horizontal

En versiones previas de Ionic existía un componente llamado ion-scroll, que permitía poner contenido para hacer scroll horizontal. Este componente se abandonó ya que se puede emular fácilmente con CSS.

<!-- ... -->
<div class="scrollX">
  @for (icon of icons; track $index) {
  <ion-button fill="clear">
    <ion-icon slot="icon-only" [name]="icon"></ion-icon>
  </ion-button>
  }
</div>
<!-- ... -->

<< Crear un proyecto Componentes (Parte 2) >>