Ionic 8 trae cambios y estos cambios implican cambiar la forma en la que trabajábamos con este framework. En este post vamos a hacer una llamada a una API con Ionic 8 (tal y como recomiendan sus desarrolladores) y vamos a mostrar la información que recibimos en nuestra aplicación.

Para este ejemplo crearemos una vista con un listado de productos tipo eCommerce, que recibiremos de la API gratuita de Dummyjson.

Instalación de Ionic y creación del proyecto

Si aún no tienes instalado Ionic y no sabes como crear el proyecto, te recomiendo que sigas esta pequeña rápida de la documentación del framework: Instalando Ionic

Cuando ejecutemos el comando de creación del proyecto, nos preguntará en qué framework dentro de Ionic queremos trabajar (Angular, React, Vue) y qué plantilla utilizar. Yo utilizaré Vue y la plantilla blank, si estás más familiarizado con otro framework, el contenido te será igual de útil, la lógica es la misma.

Creación de la vista

Para este ejemplo, utilizaremos la vista que nos crea el template blank de ionic, llamada "HomePage.vue", y borraremos el div con el ID container, que será en este lugar donde añadamos nuestros componentes para mostrar y vamos a importar los siguientes componentes de ionic (algunos ya importados por la vista de ejemplo):

<script setup lang="ts">
import {
  IonContent,
  IonHeader,
  IonPage,
  IonTitle,
  IonToolbar,
  IonCard,
  IonCardContent,
  IonCardHeader,
  IonCardSubtitle,
  IonCardTitle,
  IonLoading,
  IonToast
} from '@ionic/vue';
...
...

Los componentes que hemos añadido, aparte de los que vienen ya por defecto en la pantalla, son:

  • IonCard: Este será el componente que utilizaremos para mostrar la información de cada producto que recibamos de la API.

  • IonLoading: Este componente mostrará un loading mientras se hace la llamada a la aplicación y se ocultará en cuanto termine.

  • IonToast: Utilizaremos un toast para mostrar un mensaje de error (en el caso de que lo haya) al llamar a la API.

Nos quedaría la vista con esta estructura (las variables utilizadas las veremos a continuación)

<template>
  <ion-page>
    <ion-header :translucent="true">
      <ion-toolbar>
        <ion-title>OnShop</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content :fullscreen="true">
      <ion-header collapse="condense">
        <ion-toolbar>
          <ion-title size="large">OnShop</ion-title>
        </ion-toolbar>
      </ion-header>

      <ion-card v-for="item in itemList" :key="item.id">
        <img alt="Silhouette of mountains" :src="item.thumbnail" />
        <ion-card-header>
          <ion-card-title>{{ item.title }}</ion-card-title>
          <ion-card-subtitle>
            <ion-label>{{ item.price }}$</ion-label>
          </ion-card-subtitle>
        </ion-card-header>

        <ion-card-content>
          {{ item.description }}
        </ion-card-content>
      </ion-card>
      <ion-loading class="custom-loading" trigger="open-loading" message="Loading products"
        :isOpen="loading"></ion-loading>
      <ion-toast :is-open="showError" position="middle" color="danger"
        message="An error occurred while obtaining the products, please try again later." :duration="5000"></ion-toast>
    </ion-content>
  </ion-page>
</template>

Script de la pantalla

Ahora que ya hemos visto la estructura de nuestra pantalla, nos queda añadir la lógica para que estos componentes interactúen.

Iremos por partes, lo primero que importaremos en el script, debajo de la importación de los componentes, será la función ref de vue para hacer uso de variables reactivas, CapacitorHttp recomendada por el equipo de Ionic que es una api que parchea fetch y XMLHttpRequest, es decir, lo que utilizaremos para hacer nuestra llamada. Y también HttpReponse que es el tipo de dato que devolverá.

<script setup lang="ts">
import {
...
...
} from '@ionic/vue';
import { ref } from 'vue';
import { CapacitorHttp, HttpResponse } from '@capacitor/core';

</script>

A continuación, crearemos las variables y el tipo products:

...
...
//Tipo del producto
type Product = {
  id: number,
  title: string,
  price: string,
  description: string,
  thumbnail: string,
}
//Donde guardamos los productos
const itemList = ref<Product[]>([]);
//Controla cuando mostrar el loading
const loading = ref<boolean>(true);
//Controla la visibilidad del toast de error
const showError = ref<boolean>(false)

Y por último, y por lo que estamos aquí, la llamada a API. Crearemos la función y la llamaremos seguidamente, para en cuanto cargue la pantalla se lance la función.

const getProducts = async () => {
  const options = {
    url: 'https://dummyjson.com/products',
    // headers: { 'X-Fake-Header': 'Fake-Value' },
    // params: { color: 'red' },
  };
  try {
    const response: HttpResponse = await CapacitorHttp.get(options);
    itemList.value = response.data.products
  } catch (err) {
    showError.value = true;
  }
  loading.value = false;
};

// Llamamos a la función getProducts() para que se ejecute al cargar la vista
getProducts();

Este sería el script completo, con todas las partes comentadas:

<script setup lang="ts">
import {
  IonContent,
  IonHeader,
  IonPage,
  IonTitle,
  IonToolbar,
  IonCard,
  IonCardContent,
  IonCardHeader,
  IonCardSubtitle,
  IonCardTitle,
  IonLoading,
  IonToast
} from '@ionic/vue';
import { ref } from 'vue';
import { CapacitorHttp, HttpResponse } from '@capacitor/core';

type Product = {
  id: number,
  title: string,
  price: string,
  description: string,
  thumbnail: string,
}

const itemList = ref<Product[]>([]);
const loading = ref<boolean>(true);
const showError = ref<boolean>(false)

const getProducts = async () => {
  const options = {
    url: 'https://dummyjson.com/products',
    // headers: { 'X-Fake-Header': 'Fake-Value' },
    // params: { color: 'red' },
  };
  try {
    const response: HttpResponse = await CapacitorHttp.get(options);
    itemList.value = response.data.products
  } catch (err) {
    showError.value = true;
  }

  loading.value = false;
};

// Llamamos a la función getProducts() para que se ejecute al cargar la vista
getProducts();

</script>