sábado, 29 de mayo de 2021

Comunicación en Tiempo Real - SignalR NetCore(Backend) con Ionic-vue(Frontend) - Parte II

 En el articulo anterior construimos el backend con netcore 5 y configuramos signalr ver artículo 

Ahora construiremos el frontend y veremos como configurar signalr en nuestro cliente para poder mostrar información en tiempo real.

Lo primero que aremos será instalar el  ionic


npm install -g @ ionic / cli
Creamos nuestra aplicación

ionic start product-signalr tabs --type vue
Una vez creado nuestro proyecto instalamos el paquete que nos servirá para establecer la comunicación con signalr

npm install @ aspnet / signalr
Dentro de la carpeta src creamos un archivo api-endpoint.ts que solo tendrá una constante que representara la uri base de nuestra api para poder consumir los diferentes endpoints de la api

const url =  "http://localhost:55802";
export default url;
Dentro de la carpeta views Modificamos el archivo Tabs.vue

<template>
  <ion-page>
    <ion-tabs>
      <ion-tab-bar slot="bottom">
        <ion-tab-button tab="tab1" href="/tabs/tab1">
          <ion-icon :icon="homeOutline" />
        </ion-tab-button>
          
        <ion-tab-button tab="tab2" href="/tabs/tab2">
          <ion-icon :icon="addCircleOutline" />
        </ion-tab-button>
        
        <ion-tab-button tab="tab3" href="/tabs/tab3">
          <ion-icon :icon="informationCircleOutline" />
        </ion-tab-button>
      </ion-tab-bar>
    </ion-tabs>
  </ion-page>
</template>

<script lang="ts">
import { IonTabBar, IonTabButton, IonTabs, IonIcon, IonPage } from '@ionic/vue';
import { addCircleOutline, informationCircleOutline, homeOutline } from 'ionicons/icons';


export default {
  name: 'Tabs',
  components: {IonTabs, IonTabBar, IonTabButton, IonIcon, IonPage },
  setup() {
    return {
      addCircleOutline, 
      informationCircleOutline, 
      homeOutline,
    }
  }
}
</script>
Ahora modificamos Tab1.vue que será la vista donde cargaremos todos los productos que nos devuelve la petición Get de nuestra api, pero también estableceremos la comunicación en tiempo real con signalr para que siempre que se agregue un nuevo producto los datos se actualicen en tiempo real y nos muestre una notificación con los datos agregados.

<template>
  <ion-page>
    <ion-header>
      <ion-toolbar>
        <ion-title>Home</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content :fullscreen="true" class="ion-padding">
      <ion-list>
        <ion-list-header lines="inset">
          <ion-label>Products</ion-label>
        </ion-list-header>
        <div v-for="item in dataApi" :key="item.id">
          <ion-item>
            <ion-label>
              <h2>{{ item.name }}</h2>
              <h3>{{ item.category }}</h3>
            </ion-label>
          </ion-item>
        </div>
      </ion-list>
    </ion-content>
  </ion-page>
</template>

<script lang="ts">
import {
  IonPage,
  IonHeader,
  IonToolbar,
  IonTitle,
  IonContent,
  IonList,
  IonListHeader,
  IonLabel,
  IonItem,
  alertController 
} from "@ionic/vue";
import { ref, onMounted } from "vue";
import { HubConnectionBuilder, LogLevel } from "@aspnet/signalr";
import api from "../api-endpoint";
export default {
  name: "Tab1",
  components: {
    IonHeader,
    IonToolbar,
    IonTitle,
    IonContent,
    IonPage,
    IonList,
    IonListHeader,
    IonLabel,
    IonItem,
  },

  setup() {
    const dataApi = ref([]);
    //method get data from api
    const getData = async () => {
      try {
        const response = await fetch(`${api}/api/product`);
        dataApi.value = await response.json();
        console.log(dataApi.value);
      } catch (error) {
        console.log(error);
      }
    };
    onMounted(async() => {
      getData();

      //connection hub backend
      const connection = new HubConnectionBuilder()
        .withUrl(`${api}/product-hub`)
        .build();

      //show alert add product
      connection.on("NewProduct",async(product: {name: string; category: string; price: number}) => {
          const alert = await alertController
            .create({
              cssClass: 'my-custom-class',
              header: 'New Product',
              subHeader: product.name,
              message: JSON.stringify(product,null,'\t'),
              buttons: ['OK'],
            });
          await alert.present();

          getData();
      });
      connection.start();
    });
    return {
      dataApi,
      getData,
    };
  },
};
</script>
También modificamos Tab2.vue que será la vista donde agregaremos un nuevo producto

<template>
  <ion-page>
    <ion-header>
      <ion-toolbar>
        <ion-title>Add Product</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content :fullscreen="true" class="ion-padding">
      <ion-row class="ion-justify-content-center">
        <ion-col size="12" size-xs="12" size-sm="6" size-md="6" size-lg="6">
          <form @submit.prevent="onSubmit">
            <ion-item>
              <ion-label position="floating">Name</ion-label>
              <ion-input v-model="name"></ion-input>
            </ion-item>
            <ion-item>
              <ion-label position="floating">Category</ion-label>
              <ion-input v-model="category"></ion-input>
            </ion-item>
            <ion-item>
              <ion-label position="floating">Price</ion-label>
              <ion-input type="number" v-model="price"></ion-input>
            </ion-item>
            <div class="ion-text-center ion-padding-top">
              <ion-button type="submit" color="success" shape="round"
                >Add
              </ion-button>
            </div>
          </form>
        </ion-col>
      </ion-row>
    </ion-content>
  </ion-page>
</template>

<script lang="ts">
import {
  IonPage,
  IonHeader,
  IonToolbar,
  IonTitle,
  IonContent,
  IonRow,
  IonCol,
  IonItem,
  IonLabel,
  IonInput,
  IonButton,
  loadingController,
} from "@ionic/vue";
import { ref } from "vue";
import api from "../api-endpoint";
export default {
  name: "Tab2",
  components: {
    IonHeader,
    IonToolbar,
    IonTitle,
    IonContent,
    IonRow,
    IonCol,
    IonPage,
    IonItem,
    IonLabel,
    IonInput,
    IonButton,
  },

  setup() {
    const name = ref("");
    const category = ref("");
    const price = ref("");
    const onSubmit = async () => {
      
      const loading = await loadingController.create({
        cssClass: "my-custom-class",
        message: "Add...",
      });
      try {
        await loading.present();
  
        console.log(name.value);
          //post data api
          const requestOptions = {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ name: name.value, category: category.value, price: price.value })
          };
          const response = await fetch(`${api}/api/product`, requestOptions);
          const data = await response.json();
          console.log(data);
          name.value = "";
          category.value =  "";
          price.value = "";
      } catch (error) {
        console.log(error);
      }finally{
        await loading.dismiss();
      }

    };
    return {
      name,
      category,
      price,
      onSubmit,
    };
  },
};
</script>
Si ejecutamos nuestra aplicación obtendremos el siguiente resultado

Para poder observar la comunicación en tiempo real debemos ejecutar la aplicación en 2 pestañas diferentes del navegador en una pestaña agreguemos un producto y en la otra pestaña veremos como automáticamente después de agregar un producto nos aparece una notificación que un nuevo producto se agrego.

Para ver la aplicación funcionando realice el deploy del backend en heroku y el deploy del frontend en firebase https://product-signalr-ionic.web.app


puedes descargar el código desde este repositorio

si quieren donarme para una café lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador...

0 comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.