miércoles, 16 de junio de 2021

Todo Bootstrap 5 Vue 3

En este artículo estaremos creando el famoso todo pero lo haremos usando bootstrap 5 y vue 3, también estaremos usando localstorage para poder persistir y administrar las tareas.

El resultado final de nuestra aplicación será el siguiente

TODO APP


Lo primero que haremos será instalar la última versión de bootstrap 


npm install --save @popperjs/core bootstrap@next
En nuestro main.js debemos importar bootstrap

import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap";
Dentro de la carpeta components crearemos un nuevo componente llamado Header.vue que como su nombre lo indica será la parte del header de nuestra aplicación y el encargado de mostrar un diálogo en donde el usuario podrá ingresar su nombre

<template>
  <h4 className="bg-primary text-white text-center p-4">
    Todo App - {{name}}
  </h4>
</template>

<script>
import { onMounted, ref } from "vue";

export default {
  name: "Header",
  setup() {
    const  name = ref('');
    onMounted(() => {
      const person = prompt("Please enter your name:");
      if (person == null || person == "") {
        name.value = "Leo Messi";
      } else {
        name.value =  person ;
      }
    });
    return {
      name
    };
  },
};
</script>
Creamos otro componente llamado Tasks.vue que será el encargado de listar todas las tareas ingresadas por los usuarios, este componente también será el encargado de poder cambiar de estado las tareas a terminadas y eliminarlas

<template>
  <div class="container" v-if="tasks.length > 0">
    <div class="row">
      <div class="col bg-danger text-white">
        Pending : {{tasks.filter(t => t.done == false).length}}
      </div>
      <div class="col bg-success text-white">
        Completed : {{tasks.filter(t => t.done == true).length}}
      </div>
    </div>
  </div>
  <div v-for="(item, index) in tasks" :key="index" class="pt-2">
    <div
      :class="['alert', item.done ? 'alert-success' : 'alert-danger']"
      role="alert"
    >
      <div class="d-flex justify-content-between align-items-center">
        <div>
          <h5>{{ item.name }}</h5>
        </div>
        <div>
          <button
            type="button"
            class="btn btn-outline-success bt-sm mx-3"
            @click="editTask(index)"
          >
            <i class="bi bi-check-lg"></i>
          </button>
          <button
            type="button"
            class="btn btn-outline-danger bt-sm"
            @click="deleteTask(index)"
          >
            <i class="bi bi-x-lg"></i>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "Tasks",
  props: {
    tasks: {
      type: Array,
      default: () => [],
    },
  },

  emits: ["editTask", "deleteTask"],
  setup(props, { emit }) {
    const editTask = (index) => {
      emit("editTask", index);
    };

    const deleteTask = (index) => {
      emit("deleteTask", index);
    };
    return {
      editTask,
      deleteTask,
    };
  },
};
</script>

<style lang="scss" scoped></style>
Creamos un último componente llamado AddTask.vue que será el encargado de poder agregar nuevas tareas

<template>
  <div class="input-group my-4">
    <input
      type="text"
      class="form-control"
      placeholder="run"
      v-model="task"
      @keyup.enter="addTask"
    />
    <button class="btn btn-primary" type="button" @click="addTask">
<i class="bi bi-plus-lg"></i> 
    </button>
  </div>
</template>

<script>
import { ref } from "vue";

export default {
  name: "AddTask",

  emits: ["addTask"],
  setup(props, { emit }) {
    const task = ref('');

    const addTask = () => {
      const newTask = {
          name: task.value,
          done: false,
      }
      emit("addTask", newTask);
      task.value = "";
    };
    return {
        task,
        addTask,
    };
  },
};
</script>

<style lang="scss" scoped></style>
Ahora dentro de App.vue  usamos los componentes creados anteriormente y agregamos la funcionalidad para poder persistir la información en localstorage

<template>
  <Header />
  <div class="container">
    <AddTask @addTask="addTask" />
    <Tasks :tasks="tasks" @editTask="editTask" @deleteTask="deleteTask" />
  </div>
</template>

<script>
import Header from "@/components/Header.vue";
import Tasks from "@/components/Tasks.vue";
import AddTask from "@/components/AddTask.vue";
import { onMounted, ref } from "vue";

export default {
  name: "App",
  components: {
    Header,
    Tasks,
    AddTask,
  },

  setup() {
    const tasks = ref([]);

    onMounted(() => {
      let dataLocalStorage = JSON.parse(localStorage.getItem("tasks"));
      if (dataLocalStorage === null) {
        tasks.value = [];
      } else {
        tasks.value = dataLocalStorage;
      }
    });

    const updateLocalStorage = () => {
      localStorage.setItem("tasks", JSON.stringify(tasks.value));
    };

    const addTask = (task) => {
      tasks.value.push({
        name: task.name,
        done: task.done,
      });
      console.log(tasks.value);
      updateLocalStorage();
    };

    const editTask = (index) => {
      tasks.value[index].done = true;
      updateLocalStorage();
    };

    const deleteTask = (index) => {
      tasks.value.splice(index, 1);
      updateLocalStorage();
    };

    return {
      updateLocalStorage,
      tasks,
      addTask,
      editTask,
      deleteTask,
    };
  },
};
</script>

<style></style>

TODO APP

Puedes ver la aplicación funcionando https://todo-bootstrap-vue3.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...

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...

martes, 25 de mayo de 2021

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

En esta oportunidad estaremos aprendiendo como poder crear aplicaciones que se puedan comunicar en tiempo real desde el backend y el fronted.

Para este ejemplo Desarrollaremos una Api usando Net Core 5, para la persistencia de datos estaremos usando una Base de datos SQLite y del lado del Frontend estaremos usando Ionic-vue para consumir la api y poder actualizar la información en tiempo real usando  SignalR.

Esta será la primera parte en la cual estaremos realizando el backend.

Lo primero que aremos será crear un nuevo proyecto en visual studio tipo ASP.NET CORE Web Api al cual nombrare Products.Api



 Elegimos la plataforma .NET 5.0


Lo siguiente que aremos será instalar los siguientes paquetes Nuget para poder usar EF con SQLite


dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Tools
Crearemos nuestra clase modelo que representa nuestra tabla en  sqlite. Así que creamos una carpeta Models y dentro de esta creemos una clase llama Product


    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public Decimal Price { get; set; }
    }
Siempre dentro de la carpeta Models creemos nuestra clase context que nos servirá para poder generar nuestra db


    public class ProductContext : DbContext
    {
        public DbSet<Product> Products { get; set; }

        public ProductContext(DbContextOptions<ProductContext> options) : base(options)
        {

        }
    }
Dentro del archivo appsettings.json crearemos un ConnectionStrings e indicamos el nombre que tendrá nuestro db


  "ConnectionStrings": {
    "AppConnection": "DataSource=products.db;"
  },
Registramos el contexto en la clase Startup en el método ConfigureServices.


           services.AddDbContext<ProductContext>(options =>
                options.UseSqlite(Configuration.GetConnectionString("AppConnection")));
Creamos la migración inicial(deben tener instalado el cli de netcore dotnet tool install --global dotnet-ef)

Generamos la db


Configuremos SignalR crea una carpeta llamada Hubs y dentro crea una clase llamada ProductHub


    public class ProductHub : Hub
    {
        public async Task SendMyEvent()
        {
            await Clients.All.SendAsync("MyEvent");
        }
    }
Nuevamente en la clase Startup en el método ConfigureServices agregamos el servicio de SignalR 

services.AddSignalR();
Siempre en la clase Startup pero en el método Configure agregamos la configuración de SignalR, y también aprovechemos y agregamos la configuración de los cors.

            // global cors policy
            app.UseCors(x => x
                .AllowAnyMethod()
                .AllowAnyHeader()
                .SetIsOriginAllowed(origin => true) // allow any origin
                .AllowCredentials()); // allow credentials

            app.UseAuthorization();

            //endpoint hub signalR
            app.UseEndpoints(endpoints => endpoints.MapHub<ProductHub>("/product-hub"));
Creamos un controlador Product 

    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly ProductContext _context;
        private readonly IHubContext<ProductHub> _hubContext;

        public ProductController(ProductContext context, IHubContext<ProductHub> hubContext)
        {
            _context = context;
            _hubContext = hubContext;
        }

        [HttpGet]
        public async Task<ActionResult<List<Product>>> Get()
        {

            return await _context.Products.ToListAsync();
        }
        [HttpPost]
        public async Task<ActionResult> Post(Product product)
        {
            _context.Products.Add(product);
            await _context.SaveChangesAsync();
            await _hubContext.Clients.All.SendAsync("NewProduct", product);

            return Ok(product);
        }
    }
Como podrán notar es un controlador simple que solo cuenta con 2 peticiones una petición Get que obtendrá todos los productos y otra petición Post que agregara productos y dentro de esta hacemos uso de la clase Hub que creamos anteriormente y haciendo uso del método SendAsync que nos proporciona la librería de SignalR le pasamos el nombre del método(NewProduct) que usaremos en el frontend para obtener la información en tiempo real del producto agregado(product)

Nuestra api con signalr esta lista


puedes descargar el código desde este repositorio

En el próximo articulo estaremos creando el frontend y consumiendo la api.


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

Hasta la próxima.

Saludos desde El Salvador...

sábado, 6 de marzo de 2021

Desarrollo Móvil con Vue - Parte 3(NativeScript)

 En los artículos anteriores desarrollamos una aplicación móvil usando vue con el framework Quasar  ver articulo. y con el framework Ionic ver articulo

Este es el ultimo articulo de Desarrollo móvil con vue js y en esta ocasión usaremos el framework nativescript que a diferencia de los 2 anteriores con nativescript podremos crear aplicaciones nativas usando vue js.




Para empezar a desarrollar aplicaciones con nativescript-vue debes tener listo tu sistema operativo para el desarrollo nativo(tener instalado y configurado android studio para app android o xcode para ios ver documentación ) y t también debes tener  instalado vue-cli

 npm install -g @vue/cli @vue/cli-init
Teniendo instalado el cli de vue podremos crear nuestra app

 vue init nativescript-vue/vue-cli-template myapp-nativescript
nos aparecerán una serie de configuraciones que debemos seleccionar(en mi caso elegí lo mas básico)



Accedemos a la carpeta donde se genero nuestro proyecto y procedemos a instalar los módulos necesarios


Ya podemos abrir  nuestro proyecto en vscode, y tendremos la siguiente estructura del proyecto


Si ejecutamos nuestro proyecto

 tns run android
observaremos el famoso hello word 


Trabajaremos dentro de la carpeta src/components/App.vue colocamos el siguiente código


<template>
  <Page>
    <ActionBar title="App Users">
      <ActionItem ios.position="right">Cristian Torres</ActionItem>
    </ActionBar>
    <ListView for="item in dataApi" class="list-group">
      <v-template>
        <GridLayout class="list-group-item" rows="*" columns="auto, *">
          <Image
            src.decode="font://"
            class="fas ico"
            horizontalAlignment="left"
            style="color: green"
          />
          <StackLayout
            class="list-view-item"
            orientation="vertical"
            paddingLeft="50"
            paddingRight="50"
            paddingBotton="0"
            paddingTop="0"
            style="margin: 0"
          >
            <Label class="h3" :text="item.name" />
            <Label class="h4" :text="item.email" />
          </StackLayout>
        </GridLayout>
      </v-template>
    </ListView>
  </Page>
</template>

<script>
export default {
  data() {
    return {
      dataApi: [],
    };
  },
  async mounted() {
    //llamamos metodo para cargar la data
    this.getData();
  },
  methods: {
    //metodo para obtener la data de la api
    async getData() {
      try {
        const response = await fetch(
          "https://jsonplaceholder.typicode.com/users"
        );
        this.dataApi = await response.json();
        console.log(this.dataApi);
      } catch (error) {
        console.log(error);
      }
    },
  },
};
</script>

<style scoped>
ActionBar {
  background-color: #2b8cee;
  color: #ffffff;
}

.ico {
  color: red;
  font-size: 5;
}


.message {
  vertical-align: center;
  text-align: center;
  font-size: 20;
  color: #333333;
}
</style>

Si observamos el código veremos que el codigo javascript es muy similar al que usamos en los artículos anteriores de hecho es el mismo que usamos cuando hicimos la app con Quasar y ligeramente diferente al que usamos con Ionic, ya que ionic usa  vue 3(es un poco diferen a vue 2).
Pero si observamos el código del template(que son los componentes) si notamos que es diferente a qusar e ionic y es porque como se los dije al principio con nativescript se crean aplicaciones nativas y los componentes se parecen mas a como cuando estamos desarrollando aplicaciones nativas(ActionBar, ListView, Label etc).

Para usar iconos en nativescript debemos instalar las fuentes .ttf  icon fonts  las cuales ya van instaladas en el proyecto






Si corremos nuestra aplicación

 tns run android
obtendremos el siguiente resultado

 

El resultado de la aplicación es similar a las que desarrollamos con quasar e ionic (consumimos una api y mostramos los datos en un listview) pero a diferencia de los ejemplos anteriores el resultado de esta aplicación es nativa no hibrida.

Y con este articulo llegamos al final de la serie de artículos de desarrollo móvil con vue, en donde les mostré algunas opciones(creo que las mas populares) para poder usar las habilidades de desarrollo web con vue en aplicaciones móviles.

En próximos artículos estaremos desarrollando mas ejemplos usando nuestro querido framework de vue para desarrollo móvil

puedes descargar el código desde este repositorio




si quieren donarme para una cerveza lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador

domingo, 10 de enero de 2021

Desarrollo Móvil con Vue - Parte 2(Ionic)

En el articulo anterior desarrollamos una aplicación móvil usando vue con el framework Quasar  ver articulo.

Continuando con el desarrollo móvil con vue esta vez aremos la misma aplicación  pero usando ionicframework que al igual que Quasar con este framework podremos crear aplicaciones móviles hibridas(para android y también ios), también ionic nos permite crear aplicaciones web y aplicaciones de escritorio.




Lo primero que aremos será instalar ionic 
npm install -g @ ionic / cli
Luego de instalar el cli de ionic podremos crear nuestra aplicación con el siguiente comando
ionic start myapp-ionic  --type vue
Elegimos una plantilla en blanco

 

Esto nos creara un proyecto con la siguiente estructura.


En la carpeta que trabajaremos sera en src para ejecutar nuestra aplicación usaremos el siguiente comando(podemos usar la terminal integrada de vs code)

ionic serve


Esto desplegara la aplicación en nuestro navegador, al igual que con Quasar podremos trabajar el desarrollo de la aplicación y ejecutarla desde el navegador y una vez terminada podremos compilar para android o ios.

Lo que aremos será modificar  el archivo Home.vue que esta dentro de la carpeta Views, que es la vista con que nuestra aplicación inicia.



<template>
  <ion-page>
    <ion-header :translucent="true">
      <ion-toolbar color="primary">
        <ion-title>App Users</ion-title>
        <ion-title class="ion-text-right" size="small">Cristian Torres</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content :fullscreen="true"> 
      <ion-list>
        <ion-list-header lines="inset">
          <ion-label>Users</ion-label>
        </ion-list-header>
      <div v-for="item in dataApi" :key="item.id" >
          <ion-item>
            <ion-avatar slot="start">
              <ion-icon :icon="personCircleOutline" size="large" style="color: #26a660;">
            </ion-icon></ion-avatar>
            <ion-label>
              <h2>{{ item.name }}</h2>
              <h3>{{ item.email }}</h3>
            </ion-label>
          </ion-item>
        </div>
      </ion-list>
    </ion-content>
  </ion-page>
</template>

<script lang="ts">
import {
  IonContent,
  IonHeader,
  IonPage,
  IonTitle,
  IonToolbar,
  IonList,
  IonListHeader,
  IonLabel,
  IonAvatar,
  IonItem,
  IonIcon,
} from "@ionic/vue";
import { defineComponent, ref, onMounted } from "vue";
import { personCircleOutline } from "ionicons/icons";
export default defineComponent({
  name: "Home",
  components: {
    IonContent,
    IonHeader,
    IonPage,
    IonTitle,
    IonToolbar,
    IonList,
    IonListHeader,
    IonLabel,
    IonAvatar,
    IonItem,
    IonIcon,
  },
  setup() {
    const dataApi = ref([]);
    //metodo para obtener la data de la api
    const getData = async () => {
      try {
        const response = await fetch(
          "https://jsonplaceholder.typicode.com/users"
        );
        dataApi.value = await response.json();
        console.log(dataApi.value);
      } catch (error) {
        console.log(error);
      }
    };
    //llamamos metodo para cargar la data
    onMounted(() => {
      getData();
    });
    return {
      dataApi,
      getData,
      personCircleOutline
    };
  },
});
</script>

<style scoped>
</style>
</script> 

 Dentro de nuestro template hacemos uso de componentes de ionic  para pintar la lista de usuarios que obtenemos de la api de jsonplaceholder en nuestro método getData() si vieron el articulo anterior(quasar) verán que el código javascript es un poco diferente y eso es porque ionic usa vue 3.

Si corremos nuestra aplicación  
ionic serve


El resultado de la aplicación es similar a la que obtuvimos con quasar(claro el estilo es un poco diferente ya que cada framework usa sus propios componentes y css).

Por ultimo solo nos falta compilar nuestra aplicación para android o ios para hacer esto ionic(al igual que quasar) utiliza capacitor o cordova para generar tu aplicación móvil(capacitor es el framework oficial de ionic  para generar aplicaciones móviles y este ya viene integrado en el proyecto)

Para poder compilar tu app con capacitor debes tener instalado Android Studio para android y Xcode para ios voy a partir de que ya tienes instalado android studio en tu maquina para poder compilar para android.

Lo primero que aremos será ejecutar(se nos creara el build de nuestro proyecto y creara la carpeta dist)

ionic build
Y luego ejecutamos el siguiente comando(este comando creara la carpeta android y ios)

ionic cap add android
Por ultimo ejecutamos

ionic cap open android
Se nos abrirá nuestro proyecto en android studio, y ya podremos probar nuestra aplicacion en nuestro dispositivo o en umulador.


A diferencia de quasar(se hace con un comando del cli) si queremos generar nuestra apk lo podremos hacer desde android studio.

Y eso seria todo, como ven al igual que quasar crear una aplicación móvil con ionic es relativamente sencillo. En el siguiente articulo crearemos la misma aplicación usando Nativescript-vue.
 
Y como siempre pueden encontrar el código en github.

si quieren donarme para una cerveza lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador

sábado, 2 de enero de 2021

Desarrollo Movil con Vue (3 Opciones) - Parte 1 (Quasar)

Primeramente desearte que tengas un 2021 exitoso y con muchas líneas de código.

Para empezar este 2021 con pie derecho, te traigo una serie de articulos que de seguro te ayudaran si quieres entrar al mundo de desarrollo móvil.

Si eres desarrollador web con VUE JS y quieres empezar a desarrollar para móvil, pues que crees puedes seguir usando vue para desarrollar aplicaciones para android e ios. 

Y en esta serie de tutoriales(serán 3) te mostrare 3 opciones para el desarrollo móvil con vue js

Realizaremos una aplicación sencilla con estos 3 framework que tienen soporte para vue y que además son de código abierto, y que con los conocimientos que tienes de vue podrás empezar a desarrollar aplicaciones movil.

La decisión de cual framework elegir ya es cosa tuya de acuerdo a los requerimientos de la aplicación que quieras desarrollar, solo déjame decirme que los 3 framework te permiten compilar tanto para android como ios(yo solo are la compilación para android, pero si tu tienes una mac puedes también compilar para ios).

La aplicación que realizaremos como te lo dije anteriormente será algo sencilla, pero sin duda te servirá para que tengas una idea de como empezar con estos frameworks.





Lo que aremos será consumir la api de jsonplaceholder. para obtener una lista de  usuarios que mostraremos en un listview 

Y bueno empezaremos con Quasar que básicamente es un framework basado en vue que te sirve para desarrollar aplicaciones móviles(aplicaciones hibridas con cordova y capacitor) y que también  te permite desarrollar PWA, SPA, SSR y  Aplicaciones de Escritorio, prácticamente te permite crear todo tipo de aplicaciones con la misma base de código(te invito que le des un ojo a la documentación).
Este framework ya cuenta con una serie de componentes que te ayudan a crear aplicaciones rápidamente si ya usaste(vuetify o bootstrap-vue) te parecerá muy familiar.

Y bueno basta de explicaciones(te recomiendo que leas la documentación para entender mejor como funciona este framework) empecemos de una buena vez a lo que viniste.

Lo primero que debes hacer es instalar Quasar CLI  abrimos nuestra terminar y escribimos lo siguiente
npm install -g @quasar/cli
Una vez instalado empezaremos creando una aplicación con quasar siempre en nuestra terminal escribirnos el siguiente comando

quasar create myapp-quasar
Te saldrán una  una serie de preguntas para la configuración de tu proyecto que debes completar en mi caso deje casi todo por defecto, solo cambie el preprocesador de css por scss y no inclui a eslint 





Una vez creado nuestro proyecto abrimos la carpeta con nuestro editor favorito en mi caso vscode
si vemos la estructuras de las carpetas son muy parecidas a crear un proyecto con vue cli 


En la carpeta que trabajaremos sera en src, para ejecutar nuestra aplicación usaremos el siguiente comando(podemos usar la terminal integrada de vscode)
quasar dev


Esto desplegara la aplicación  que por defecto que  trae la plantilla de  quasar en nuestro navegador, lo bueno de esto es que podemos desarrollar toda nuestra aplicación y ejecutarla desde el navegador(de preferencia en versión movil) y una vez terminada podemos compilar para android o ios.

Lo que aremos es modificar dentro de la carpeta pages el archivo Index.vue que es la vista de inicio de nuestra aplicación.

<template>
  <q-page class="q-pa-md">
    <!--componente listview quasar-->
    <q-list bordered="" padding="">
      <q-item-label header="">Users</q-item-label>
      <div :key="item.id" v-for="item in dataApi">
        <q-item>
          <q-item-section avatar="" top="">
            <q-icon class="text-secondary" name="account_circle" style="font-size: 30px;">
          </q-icon></q-item-section>

          <q-item-section>
            <q-item-label>{{ item.name }}</q-item-label>
            <q-item-label caption="">{{ item.email }}</q-item-label>
          </q-item-section>
        </q-item>
        <q-separator inset="item" spaced="">
      </q-separator></div>
    </q-list>
  </q-page>
</template>

<script>
export default {
  name: "PageIndex",

  data() {
    return {
      dataApi: [],
    };
  },
  async mounted() {
    //llamamos metodo para cargar la data
    this.getData();
  },
  methods: {
    //metodo para obtener la data de la api
    async getData() {
      try {
        const response = await fetch(
          "https://jsonplaceholder.typicode.com/users"
        );
        this.dataApi = await response.json();
        console.log(this.dataApi);
      } catch (error) {
        console.log(error);
      }
    },
  },
};
</script>
Dentro de nuestro template hacemos uso de un componente de quasar List and List Items que nos sirve para listar los datos que obtenemos de la api, que es lo que hacemos con nuestro metodo getData() mediante fetch hacemos un get para obtener un listado de usuarios que jsonplaceholder nos  ofrece.
Si corremos nuestra aplicación con el comando que ya lo hicimos anteriormente.

quasar dev
obtendremos el siguiente resultado.



Ahora solo nos falta copilar nuestra aplicación para android o ios para hacer esto quasar utiliza cordova o capacitor para generar tu aplicación móvil(pero no te preocupes es muy fácil hacerlo), en mi caso usare capacitor.

Para poder compilar tu app con capacitor debes tener instalado Android Studio para android y Xcode para ios Preparation for Capacitor App voy a partir de que ya tienes instalado android studio en tu maquina para poder compilar para android.

Lo primero que aremos es agregar capacitor en nuestro proyecto 

quasar mode add capacitor


Para poder probar nuestra aplicación en un emulador o en nuestro celular ejecutamos el siguiente comando(importante elegir la ip de su maquina).

quasar dev -m capacitor -T android
Este comando creara nuestro proyecto android y abrirá android studio en donde podremos ejecutar la aplicación  desde un emulador de android o desde nuestro celular.


Por ultimo solo nos queda generar el apk de nuestra app para que nuestros usuarios la puedan instalar en sus dispositivos.

quasar build -m capacitor -T android -debug
esto generara nuestro apk que se encontrata dentro de la carpeta myapp-quasar\dist\capacitor\android\apk\debug.

Como ven crear una aplicación movil con Quasar es muy sencillo, en el proximo articulo estaremos haciendo la misma aplicación pero con Ionic asi que esten pendientes.
 
Y como siempre pueden encontrar el código en github.

si quieren donarme para una cerveza lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador