Introducción a Ionic Framework
1 ¿Qué es Ionic? Historia y características principales
Ionic es un framework open source que permite crear aplicaciones móviles, de escritorio y web usando tecnologías web estándar: HTML, CSS y JavaScript/TypeScript.
La primera versión apareció en 2013 construida sobre AngularJS y Apache Cordova (un framework de desarrollo móvil originalmente conocido como PhoneGap).
Las versiones más modernas hacen uso de componentes web utilizando StencilJs, pudiendo elegir entre Angular, React o Vue.
Para acceder a las funcionalidades nativas del dispositivo (cámara, GPS, almacenamiento, etc.) hace uso de Capacitor (antes Cordova)
Principales características:
- Multiplataforma: una sola base de código para Android, iOS y PWA (Progressive Web App).
- Gran biblioteca de componentes UI listos para usar.
- Compatible con frameworks modernos (Angular, React, Vue).
- Integración con APIs nativas mediante Capacitor.
2 Arquitectura de una aplicación Ionic
Una aplicación Ionic se organiza en torno a:
- Componentes UI (components): elementos visuales (botones, listas, formularios).
- Páginas (pages): vistas que representan pantallas de la app.
- Módulos: organizan y agrupan páginas y servicios.
- Servicios: lógica de negocio y acceso a datos.
- Capacitor: puente entre JavaScript y las APIs nativas del dispositivo.
Una page es un componente con un HTML más elaborado y con una ruta añadida.
Teniendo en cuenta esto, se pueden crear componentes propios que pueden ser reutilizables en nuestra aplicación, por lo que es importante haber realizado un estudio de cada vista/pantalla que va a tener nuestra aplicación.
Al reutilizar estos componentes, conseguimos:
- Evitar duplicidad en el código.
- Mantenimiento y depuración más sencilla. Se puede modificar un componente sin modificar el resto de la aplicación.
- Al ser componentes autocontenidos, también podemos reutilizarlos entre proyectos.
3 Cómo desarrollar con Ionic
Para poder desarrollar una aplicación con Ionic necesitamos tener instalado:
- Node.js: es un entorno de ejecución que nos permite ejecutar código JavaScript fuera de un navegador. Muy conocido en entornos de desarrollo web gracias al gestor de paquetes npm.
- El CLI de Ionic, que lo instalaremos a través del gestor npm.
- Para poder compilar aplicaciones Android, necesitaremos tener Android Studio.
- Para entornos iOS/Apple, es necesario tener un ordenador Mac con Xcode y Cocoapods.
Crear primera aplicación Ionic
4 Crear primera aplicación
En esta sección se va a explicar cómo crear una primera aplicación de pruebas y cómo usarla a través del navegador web, compilarla para Android e iOS.
4.1 Preparar proyecto
Anteriormente se ha definido cómo instalar Node.js, por lo que es imprescindible asegurar que lo tenemos instalado.
Se va a realizar un resumen de la documentación oficial, por lo que para futuras versiones es conveniente ver si ha habido cambios.
4.2 Generar aplicación
Estando dentro del contenedor, vamos a instalar el paquete de Ionic a través del gestor npm:
Instalar dependencias
ruben@vega:~$ npm install -g @ionic/cli
ruben@vega:~$ npm -g ls
/usr/local/lib
+-- @ionic/cli@7.2.1
+-- corepack@0.34.0
`-- npm@11.6.0
ruben@vega:~$ ionic version
7.2.1
De esta manera tenemos instalado, de manera global, el CLI de Ionic, por lo que ya podremos crear nuestra primera aplicación. A la hora de crear un proyecto, podemos pasar utilizar ciertos parámetros, o dejar que el asistente nos pregunte:
Crear proyecto
ruben@vega:~$ ionic start
Nos realizará una serie de preguntas para generar el proyecto:
- Use the app creation wizard?: Sirve para utilizar el asistente web para generar el proyecto y así poder enlazarlo con GitHub, GitLab o Bitbucket. Vamos a elegir NO, para poder seguir con el CLI.
- Framework: Podemos elegir entre Angular, React o Vue. Elegiremos Angular.
- Project name: Elegiremos el nombre del proyecto.
- Starter template: Nos deja elegir entre distintos templates como referencia:
- tabs: una aplicación con tres pestañas en el pie de página.
- sidemenu: la aplicación cuenta con un panel lateral, que dependiendo del tamaño de la pantalla se visualizará o estará oculto.
- blank: una aplicación vacía.
- list: la aplicación tiene un listado.
- Tipo de componentes: al elegir Angular, nos pregunta si queremos crear componentes Standalone o de tipo NgModules. Elegiremos Standalone, ya que es la opción por defecto actual con Angular.
Una vez terminado el asistente nos creará un directorio con el nombre elegido, dentro de él el esqueleto del proyecto, instalará las dependencias necesarias y nos creará un proyecto git para poder subirlo a nuestro repositorio central.
Es un buen momento para usar Visual Studio Code y acceder al directorio del proyecto.
4.3 Ejecutar proyecto
Una vez generado el proyecto, es momento de ejecutar el proyecto, en este caso, de momento será una aplicación web:
Instalar dependencias
ruben@vega:~/Test $ ionic serve
> ng run app:serve --port=8100
# ...
[INFO] Development server running!
Local: http://localhost:8100
Use Ctrl+C to quit this process
[ng] - Local: http://localhost:8100/
[ng] - press h + enter to show help
De esta manera se generarán los assets (CSS y javascripts) necesarios para que la aplicación funcione. Si todo va bien, arrancará el servidor y podremos conectarnos al puerto 8100.
5 Compilar para Android
Para poder compilar el proyecto para Android necesitamos realizar los siguientes pasos, tal como nos dice la documentación oficial:
- Instalar dependencias
- npm install @capacitor/android
- Añadir al proyecto la intención de compilar para Android
- ionic capacitor add android
- Sincronizamos los assets en el proyecto Android
- ionic capacitor sync
- Abrimos el proyecto en Android Studio
- ionic capacitor open android
Desde Android Studio debemos generar el proyecto, ya que no lo genera por defecto, y ya se podrá compilar y se abrirá el emulador.
6 Compilar para iOS
Los pasos son muy parecidos a los realizados para Android, y se pueden ver en la documentación:
- Instalar dependencias
- npm install @capacitor/ios
- Necesitamos tener instalado CocoaPods, y para ello necesitamos una versión actualizada del lenguaje de programación Ruby (se recomienda usar Brew para realizar la instalación).
- gem install cocoapods
- Añadir al proyecto la intención de compilar para iOS
- ionic capacitor add ios
- Sincronizamos los assets en el proyecto iOS
- ionic capacitor sync
- Compilar proyecto, previamente nos pregunta por el emulador que queremos utilizar:
- ionic capacitor run ios
7 Usar la aplicación
Aunque sólo hemos generado una aplicación de pruebas, podemos ver el resultado en distintas plataformas. Con el mismo código, las vistas generadas son ligeramente diferentes, simulando una aplicación nativa.



Misma aplicación en navegador, Android e iOS
Estructura y componentes básicos
8 Esqueleto del proyecto
Al crear un proyecto con Ionic, se genera una estructura de directorios organizada. La más importante es la carpeta src, donde se encuentran los ficheros que vamos a desarrollar para la aplicación.
En la raíz del proyecto existen distintos ficheros que son habituales en otros proyectos modernos de desarrollo web, y otros que son específicos de Ionic.
Genera un nuevo proyecto de tipo “blank” para utilizar a partir de ahora.
El fichero principal del proyecto es ionic.config.json, que de momento sólo contiene lo siguiente:
Fichero de configuración principal
{
"name": "Blank",
"integrations": {
"capacitor": {}
},
"type": "angular-standalone"
}
No vamos a adentrarnos en el resto de momento, pero es interesante echarles un ojo, ya que el contenido puede darnos una idea de configuraciones globales utilizadas.
10 Estilos y colores
Ionic permite personalizar el aspecto de la aplicación usando CSS utilities y variables globales. Por defecto cuenta con un estilo predeterminado que cuenta con colores y valores predefinidos, pero que podemos sobreescribir.
En el archivo src/theme/variables.scss podemos sobreescribir los valores de los colores principales:
Fichero del módulo
:root {
--ion-color-primary: rgb(37, 219, 207);
--ion-color-secondary: #3dc2ff;
--ion-color-tertiary: #5260ff;
}
Ejemplo con componentes
11 Componentes UI básicos
Para poder realizar nuestra aplicación Ionic nos proporciona una colección de componentes UI que se adaptará al tipo de dispositivo en el que nos encontremos.
Para cada componente se explica cómo utilizarlo (pudiendo elegir el framework correspondiente) y también con una previsualización de cómo quedaría en su correspondiente sistema.
12 Ejemplo de componente y tema
A modo de ejemplo se va a explicar cómo añadir a la vista home un toggle para alternar el tema entre modo claro y oscuro, basado en la documentación.
Lo primero es añadir el toggle a la vista src/app/contacto/contacto.page.html:
Añadir toggle a la vista
<ion-list [inset]="true">
<ion-item>
<ion-toggle (ionChange)="toggleChange($event)"
justify="space-between">
Dark Mode
</ion-toggle>
</ion-item>
</ion-list>
Cuidado al copiar-pegar código, ya que no se realizan los imports, y dará error.
Nos aseguramos que en el fichero src/app/contacto/contacto.page.ts se han añadido los imports correspondientes a cada componente nuevo que estamos utilizando, y aparte añadimos la lógica necesaria:
Añadir lógica
export class HomePage {
paletteToggle = false;
constructor() {}
// Check/uncheck the toggle and update the palette based on isDark
initializeDarkPalette(isDark: boolean) {
this.paletteToggle = isDark;
this.toggleDarkPalette(isDark);
}
// Add or remove the "ion-palette-dark" class on the html element
toggleDarkPalette(shouldAdd: boolean) {
document.documentElement.classList.toggle('ion-palette-dark', shouldAdd);
}
// Listen for the toggle check/uncheck to toggle the dark palette
toggleChange(event: CustomEvent) {
this.toggleDarkPalette(event.detail.checked);
}
}
Sólo nos queda modificar cómo vamos a hacer uso del sistema dark mode, ya que en Ionic existen tres modos distintos:
- always: nuestra aplicación siempre estará en modo oscuro.
- system: tiene en cuenta el modo en el que se encuentra nuestro sistema.
- class: usando una clase CSS, apropiada para el caso que nos ocupa.
Para modificar este comportamiento debemos comprobar el fichero src/global.css y asegurar que descomentamos el fichero adecuado.
Añadir lógica
// @import "@ionic/angular/css/palettes/dark.always.css";
@import "@ionic/angular/css/palettes/dark.class.css";
// @import '@ionic/angular/css/palettes/dark.system.css';


Cómo quedan las modificaciones realizadas
Introducción a Typescript
13 Introducción
TypeScript (TS) es un lenguaje de código abierto desarrollado por Microsoft que se basa en JavaScript (realmente es un superconjunto de este), añadiendo tipado estático y características propias de lenguajes orientados a objetos como clases, interfaces o módulos.
El código que generamos se transpila a JavaScript (el código fuente se convierte a código JavaScript), por lo que puede ejecutarse en cualquier navegador o entorno que soporte JS.
Hoy en día se usa para crear aplicación tanto en entorno cliente como para entorno servidor (para React.js, Node.js…). Desde la versión 2 de Angular está desarrollado en TypeScript, ya que la primera versión (llamada AngularJS), se desarrollaba con JavaScript.
Hay una amplia documentación del lenguaje y en la web del W3School también existe un tutorial completo. A continuación sólo se van a explicar ciertos conceptos básicos para tener una guía de referencia básica.
13.1 Ventajas de usar TypeScript
Entre las ventajas que nos podemos encontrar al usar TypeScript, se pueden destacar las siguientes:
- Detección de errores en tiempo de desarrollo gracias al tipado.
- Código más legible y mantenible.
- Autocompletado y ayuda contextual en el editor (por ejemplo, VS Code).
- Compatibilidad total con JavaScript: cualquier código JS válido también lo es en TS.
14 Declaración de variables
Para declarar variables existen diferentes maneras en TypeScript:
- var o sin asignación: no recomendado
- Es la forma tradicional de declarar variables en JavaScript.
- Tiene ámbito de función, no de bloque.
- Puede redefinirse y reasignarse libremente.
- Puede provocar errores difíciles de detectar.
- let:
- Introducido con ES6 (2015).
- Tiene ámbito de bloque: solo existe dentro del bloque donde se define.
- Puede reasignarse, pero no re-declararse en el mismo bloque.
- Es la opción más usada para variables que cambian de valor.
- const
- También introducido con ES6.
- Tiene ámbito de bloque, igual que
let. - No puede reasignarse (su valor no puede cambiar).
- Ideal para valores que deben permanecer constantes.
| var | let | const | |
|---|---|---|---|
| Ámbito (scope) | Función | Bloque | Bloque |
| Re-declaración permitida | Sí | No | No |
| Re-asignación permitida | Sí | Sí | No |
| Uso recomendado | Evitarlo | Para variables que cambian | Para valores fijos o referencias |
En el siguiente apartado veremos ejemplos de cómo se declaran las variables.
15 Tipos de datos
En la documentación oficial se explican todos los tipos de datos que se pueden utilizar en TypeScript. A continuación se van a detallar algunos de ellos
15.1 Tipos simples
TypeScript cuenta con tres tipos de datos simples:
- string: para representar cadenas de texto
- number: para tipos numéricos. No existe distinción como en otros lenguajes para int o float, aunque sí existe para bigint. También soporta números en binario, octal y hexadecimal:
- boolean: para tipos que sólo pueden ser true o false.
Existen otros tipos de datos especiales:
- any: desactiva el control de tipos. Se recomienda evitarlo salvo en casos especiales (uso de código que no se ha escrito en TypeScript, o librerías de terceros).
- unknown: es la contrapartida a any, ya que aunque puede ser de cualquier tipo, mantiene el tipado seguro.
- undefined: se puede asignar a cualquier tipo, pero es un tipo propio.
- null: igual que el anterior.
Ejemplos de declaración de variables y tipos
const nombre: string = "Rubén";
const pi: number = 3.1415;
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;
let activado: boolean = true;
15.2 Tipos complejos
Existen otros tipos de datos, también habituales en otros lenguajes de programación.
15.2.1 Arrays
Como en otros lenguajes, podemos crear arrays del mismo tipo de datos. A la hora de declararlo, en cambio, se puede hacer de tres maneras:
Declarar un array
// se infiere que el tipo es number[]
let prueba = [1, 2, 3];
// define un array con elementos de tipo number
let prueba2: number[] = [1,2, 3];
// usa la clase Array, indicando que contendrá datos number
let prueba3: Array<number> = [1, 2, 3];
15.2.2 Tuplas
Una tuple (o tupla) es un tipo de array con una largura y un tipo de datos para cada posición predefinida. Se pueden nombrar las posiciones, para ayudar a la comprensión, pero no afecta al funcionamiento
Declarar una tuple
// definir la tupla
let ejemplo: [number, boolean, string];
// inicializar con datos correctos
ejemplo = [5, false, 'Mi texto'];
let direccion: [calle: string, n: number];
15.2.3 Objetos propios: type e interface
Al igual que pasa en JavaScript, podemos crear objetos propios, siendo una colección de parejas clave-valor. La ventaja es que podremos especificar el tipo de datos para cada propiedad del objeto. Otra característica de TypeScript es que podemos crear objetos con propiedades opcionales
Crear un objeto propio
const coche: { marca: string, year?: number } = {
marca: "Toyota"
};
car.year = 2000;
La propiedad year es opcional porque le hemos puesto el símbolo de interrogante ?. Al ser opcional, durante la asignación inicial podemos no asignarle valor.
Para poder reutilizar un tipo de objeto, podemos usar interface, lo que también nos permite crear nuevos objetos extendiendo otros ya creados.
Crear y extender un objeto
interface Rectangle {
height: number,
width: number
}
interface ColoredRectangle extends Rectangle {
color: string
}
const coloredRectangle: ColoredRectangle = {
height: 20,
width: 10,
color: "red"
};
Con type podemos crear tipos personalizados, que pueden tener un valor prefijado.
Crear y extender un objeto
type Rol = "admin" | "usuario" | "invitado";
let rolActual: Rol = "usuario";
La palabra reservada type también puede utilizarse para crear otros tipos de objetos. Se recomienda leer los siguientes enlaces para poder ver todas las posibilidades:
- w3cshcools: explica las diferencias entre type e interface.
- cheatsheets explicando las posibilidades de type e interface.
Los objetos declarados con type e interface tienen ciertas diferencias, explicadas en la documentación.
15.2.4 Enum
Los enum son un tipo de clase especial que representa un grupo de constantes, y que no se pueden modificar. Pueden ser de tipo string o numéricos.
Los enum numéricos los podemos inicializar o pueden inicializarse solos empezando por 0.
Enum inicializado
enum Direction {
Up = 1,
Down,
Left,
Right,
}
Enum sin inicializar
enum Direction {
Up,
Down,
Left,
Right,
}
Enum de texto
enum Direction {
Up = "UP",
Down = "DOWN",
}
El resto de constantes tendrán un valor auto-incremental partiendo del valor inicial (sea 0, o el que hayamos puesto). En el caso de crear un enum de tipo string, cada miembro debe ser inicializado con un texto.
16 Estructuras básicas
A continuación se van a explicar las estructuras básicas, que son iguales que en JavaScript.
16.1 Estructuras condicionales
A continuación las estructuras condicionales más habituales. Como en otros lenguajes de programación, se pueden hacer uso de los operadores lógicos && (AND), || (OR) y ! (NOT). También existe la posibilidad de utilizar el operador ternario: condition ? siTrue : siFalse .
A la hora de manejar una gran cantidad de condiciones, en lugar de usar if-else, lo ideal es hacer uso del sistema switch-case .
También tenemos las palabras reservadas break para salir de la función y default que se ejecutará cuando no coincide con ninguno de los casos expresados.
Condicional if
let num: number = 20;
if (num > 18) {
console.log("Mayor");
}
Condicional if-else
let num: number = 10;
if (num > 18) {
console.log("Mayor");
} else {
console.log("Menor");
}
Condicional else if
let num: number = 20;
if (num < 18) {
console.log("Pequeño");
} else if (num > 65) {
console.log("Muy mayor");
}
Estructura switch-case
let num: number = 18;
switch(num){
case 7:
console.log("Siete");
break;
default:
return "Otro numero";
}
16.2 Bucles
Existen distintos tipos de bucles. El bucle for es utilizado cuando conocemos previamente el número de veces que queremos itera, y también se puede utilizar para recorrer un array.
Dentro de los bucles, y utilizando una condicional, podemos usar continue si queremos omitir parte del bucle y saltar a la siguiente iteración.
Bucle for
for (let i = 0; i < 5; i++) {
console.log(`Contador ${i}`);
}
Bucle for y array
const frutas: string[] = ["Manzana", "Pera"];
for (let i = 0; i < frutas.length; i++) {
console.log(`Fruta ${i + 1}: ${frutas[i]}`);
}
Bucle for…of y array
const frutas: string[] =
["Manzana", "Pera"];
for (const f of frutas) {
console.log(`Fruta: ${f}`);
}
Bucle for…in
const p = {
name: "Ruben",
job: "Teacher"
};
for (const key in p) {
console.log(`${key}:
${p[key as keyof typeof p]}`
);
}
Existe la variante for…of que nos permite iterar sobre los elementos de colecciones, como son los Arrays ([]), Strings (“”), Mapas (Map) y Conjuntos (Set). Y para poder iterar entre las propiedades de un objeto existe for…in, de esta manera tendremos acceso a sus posibles key y values.
También podemos hacer uso de bucles while y do-while.
Bucle while
while (condición) {
// Código
}
Bucle do-while
do {
// Código
} while (condición);
17 Funciones y parámetros
A la hora de crear funciones debemos especificar los parámetros y los tipos de objetos que tienen. Los parámetros pueden ser:
- Tener valores prefijados: se puede especificar el valor por defecto de un parámetro, por lo que se puede llamar a la función sin especificarlo.
- Opcionales: los parámetros pueden ser opcionales, si se especifica con el símbolo de interrogante ?.
En caso de que las funciones devuelvan un dato, también hay que especificar el tipo de datos que va a devolver. En caso de que no devuelva ningún tipo de datos, se usará void.
Enum de texto
function sumar(a: number, b: number = 10): number {
return a + b;
}
function saludar(nombre: string, mensaje?: string): void {
console.log(mensaje ? `${mensaje}, ${nombre}` : `Hola, ${nombre}`);
}
console.log(sumar(2)); // 12
console.log(sumar(3, 5)); // 8
saludar("Ana"); // Hola, Ana
saludar("Bob", "Buenas"); // Buenas, Bob
18 Clases y métodos
TypeScript permite usar clases, constructores y métodos, como en otros lenguajes de programación orientado a objetos tradicionales. La sintaxis de una clase, los objetos y los métodos se realiza de manera similar a otros lenguajes.
Ejemplo de clase
class Persona {
private nombre: string;
private edad: number;
public constructor(nombre: string, edad: number) {
this.nombre = nombre;
this.edad = edad;
}
saludar() {
console.log(`Hola, soy ${this.nombre} y tengo ${this.edad} años.`);
}
}
const persona1 = new Persona("Bob", 30);
persona1.saludar();
Los atributos y los métodos de una clase pueden tener distinta “visibilidad”:
- public: El valor por defecto. Se permite el acceso desde cualquier lugar.
- private: Permite el acceso a los miembros de la clase sólo desde la propia clase.
- protected: Permite el acceso al miembro de la clase desde sí mismo y desde cualquier clase que lo herede.
18.1 Herencia
Como en otros lenguajes de programación orientada a objetos, también se permite la herencia de una clase “padre”. Se permite expandir la funcionalidad con:
- implements: en la documentación se explica su uso, que sirve para comprobar que se satisface una interface concreta.
- extends: para extender una clase padre. La nueva clase contiene todos los atributos y métodos de la clase original, pudiendo añadir nuevos miembros.
19 Módulos e importaciones
TypeScript organiza el código en módulos. Cada archivo puede exportar variables, funciones o clases, e importarlas en otros archivos.
Ejemplo de clase exportada
// archivo: operaciones.ts
export function multiplicar(a: number, b: number): number {
return a * b;
}
// archivo: main.ts
import { multiplicar } from './operaciones';
console.log(multiplicar(4, 5)); // 20
De esta manera es cómo funciona Angular para importar componentes, servicios o módulos.