Aplicación ElectroThings para la Gestión de Productos Electrónicos implementada con HTML5, CSS3, SCSS, Angular, Bootstrap, Highchart, Spring-Boot, Spring Security, Spring MVC, Microservicios, SpringFox, Swagger UI, Git, DBeaver, PgAdmin, PostgreSQL y Otras Tecnologías.
Ver
1.0) Descripción 🔝
Ver
- Esta aplicación ha sido desarrollada para la gestión de productos de electrónica general ( televisores, notebooks, accesorios, etc). También se ha pensado originalmente desarrollar una sección para la gestión de usuarios, pero esta funcionalidad se aplica desde el backend (Api), utilizando postman o swagger ui, al implementar un modelo de negocios únicamente para un MicroFrontEnd se deberá desarrollar otra app para la gestión de dichos usuarios.
- Como sistema de seguridad para manejo de recursos de la app se usa Spring Security y JWT. Las Operaciones Transaccionales fueron modificadas para que solamente los administradores del sistema tengan acceso, los usuarios convencionales solamente podrán visualizar los productos y filtrar búsquedas acerca de estos según el requerimiento deseado.
- Todos los formularios aplican validaciones de carácteres, longitudes, tamaños, valores numéricos, valores mal formados, email, contraseña, url de imágenes, etc.
- Se implementa Paginación Completa.
- Se aplican dos filtros de búsqueda, uno para productos de forma genérica y otro según el campo deseado, permitiendo coincidencias de carácteres y palabras.
- Para la experiencia de usuario se utiliza Popupts, Loaders, Angular Material, Etc.
- Es posible descargar el Listado de Productos Paginado en formato xlsx(excel), csv y pdf.
- Todas las Páginas de la Aplicación poseen modals de Ayuda.
- Entre Otros Recursos Disponibles.
- Aclaración : Este Microfrontend no es responsive. El enfoque es la funcionalidad de la aplicación, la maquetación es totalmente aplicable en relación al tiempo de disponibilidad que se emplee.
- Repositorio ApiRest_ElectroThingsV1
- Repositorio db_ElectroThings_MongoDB
- PlayList del Proyecto
1.1) Ejecución del Proyecto 🔝
Ver
- Crear un entorno de trabajo a través de algún IDE
- Clonar el Proyecto (
git clone https://github.com/andresWeitzel/AppElectroThings_Angular_SpringBoot_MongoDB
) - Posicionarnos sobre el proyecto
cd proyecto
- Dentro del directorio instalar todos los plugins implementados
npm i
- Ejecutar la base de datos
- Ejecutar la api rest
- Ejecutar el proyecto
ng serve
1.2) Tecnologías 🔝
Ver
Tecnologías FRONTEND | Versión | Finalidad |
---|---|---|
HTML | 5.0 | Lenguaje de Hipertexto |
Css | 3.0 | Lenguaje de hojas de estilo para presentación de documentos. |
Scss | 1.57 | Preprocesador de css. |
Angular | 13.3.0 | FrameWork Web Desarrollo de Apps con TypeScript |
Angular CLI | 13.3.0 | Herramienta de Angular para depurar, crear, publicar, etc Apps |
Angular Material | 13.3.9 | UI librería de componentes |
ng-angular-popup | 0.1.2 | Mensajes emergentes personalizados |
ngx-ui-loader | 13.0.0 | Animaciones de carga |
Highchart | 13.3.9 | Librería para la generación de gráficos |
Bootstrap | 5.1 | FrameWork Web Diseño y Desarrollo de Apps |
Visual Studio Code | 1.51.1 | Entorno de Desarrollo |
Tecnologías BACKEND | Versión | Finalidad |
---|---|---|
Java | 12.0.2 | JDK |
Spring Tool Suite 4 | 4.9.0 | IDE |
Spring Boot | 2.6.4 | Framework |
Spring Boot Data JPA | 2.6.3 | Mapeo de objetos y persistencia en la db |
Spring Security | 2.6.7 | Servicios de Seguridad |
JSON Web Token | 0.9.1 | Creación de tokens de acceso |
Maven | 4.0.0 | Gestor de Proyectos |
Postman | 9.4.1 | Test de Apis |
Lombok | 1.18.22 | Automatización de Código |
Open-Api | 1.6.4 | Documentación de la Api |
UI Swagger | 1.6.4 | Visualización y Gestión de la Api |
GNU bash / Terminal | 4.4.23 | Bash / Terminal para el manejo e implementación de Git integrado al Spring Tool Suite |
Git | 2.29.1 | Control de Versiones |
Tecnologías DATABASE | Versión | Finalidad |
---|---|---|
MongoDB | 5.0 | Base de Datos |
MongoDB Compass | 1.31.2 | Gestor para MongoDB |
2.0) EndPoints 🔝
Ver
- http://localhost:8098/api/v1/auth/login (Autenticación)
- http://localhost:8098/api/v1/auth/signin (Registro)
- http://localhost:8098/api/v1/productos/ (Agregar)
- http://localhost:8098/api/v1/productos/{id} (Editar)
- http://localhost:8098/api/v1/productos/{id} (Eliminar)
- http://localhost:8098/api/v1/productos/listado (Listado Paginado)
- http://localhost:8098/api/v1/productos/last-producto (Último Producto)
- http://localhost:8098/api/v1/productos/listado-filter/{filtro} (Listado paginado con filtro)
- http://localhost:8098/api/v1/productos/codigo/{codigo} (Listado paginado según su código)
- http://localhost:8098/api/v1/productos/nombre/{nombre} (Listado paginado según su nombre)
- http://localhost:8098/api/v1/productos/descripcion/{descripcion} (Listado paginado según su descripción)
- http://localhost:8098/api/v1/productos/categoria/{categoria} (Listado paginado según su categoria)
- Revisar Swagger para visualizar el resto de los endpoints
- http://localhost:8098/api/v1/admin/usuarios/ (Agregar)
- http://localhost:8098/api/v1/admin/usuarios/{id} (Editar)
- http://localhost:8098/api/v1/admin/usuarios/{id} (Eliminar)
- http://localhost:8098/api/v1/admin/usuarios/listado (Listado)
2.1) Recursos y Servicios 🔝
Ver
Documentación Gráfica Acotada por razones de simplificación de documentación. Visualizar los videos desde la PlayList acerca de las Pruebas de Funcionalidad de la aplicación.
3.0) Prueba de Funcionalidad 🔝
Ver
Comprobación login de usuarios (Ver)
Comprobación signin de usuarios (Ver)
Comprobación token y refresh token (Ver)
Comprobación listado de productos (Ver)
Comprobación búsqueda de productos con filtro (Ver)
3.1) Referencias 🔝
Ver
- Api Rest Spring Boot Mongodb : https://www.youtube.com/watch?v=OtBukxJy4kg
- Api Rest Guía Spring Boot Mongodb Codigo :https://github.com/heroe-geek/rest-api-springboot-mvc/blob/master/src/main/java/com/hg/crud/controllers/ProductController.java
- Tutorial MongoDB con Spring Boot : https://www.mongodb.com/compatibility/spring-boot
- Tutorial Spring Data MongoDB (01) : https://stackabuse.com/spring-data-mongodb-guide-to-the-aggregation-annotation/
- Tutorial Spring Data MongoDB(02) : https://blog.marcnuri.com/spring-data-mongodb-implementacion-de-un-repositorio-a-medida
- Tutorial Uso de Queys en MongoDB : https://www.baeldung.com/queries-in-spring-data-mongodb
- Código Ejemplo genérico : https://github.com/heroe-geek/rest-api-springboot-mvc/blob/master/src/main/java/com/hg/crud/models/ProductDTO.java
- Config Mongo y Spring Boot : https://hevodata.com/learn/spring-boot-mongodb-config/
-
Angular Popup : https://www.npmjs.com/package/ng-angular-popup
-
Angular Material : https://material.angular.io/guide/getting-started
-
Angular Bootstrap Validation
- Instalación : https://mdbootstrap.com/docs/b5/angular/getting-started/installation/
- Implementación/ejemplos : https://mdbootstrap.com/docs/b5/angular/getting-started/installation/
- Validation Forms(tanto bootstrap 4 como 5) : https://mdbootstrap.com/docs/angular/forms/validation/
-
ngx ui loader
- Instalación : https://www.npmjs.com/package/ngx-ui-loader
- Implementación : https://tdev.app/ngx-ui-loader
-
Scrollspy
- Implementación : https://mdbootstrap.com/docs/angular/navigation/scrollspy/#example-4
-
Hide Navbar
- Implementación : https://www.w3schools.com/HOWTO/howto_js_navbar_hide_scroll.asp
-
Excel Sheets
- Instalación y Doc : https://www.npmjs.com/package/xlsx
- Ejemplo Base : https://www.delftstack.com/howto/angular/angular-export-to-excel/
-
JSPDF
-
Gráficos con Highchart
- Npm, config, detalles, etc : https://hackthestuff.com/article/how-to-use-highcharts-in-angular-12
- Doc Oficial : https://api.highcharts.com/highcharts/
- Doc Oficial Instalación : https://www.highcharts.com/docs/getting-started/install-from-npm
-
Tipos de Gráficos Highchart
- Nuevo sitio Tipos de Graf : https://www.highcharts.com/blog/chartchooser/
- Ejemplo Base 2d : https://stackblitz.com/edit/highcharts-angular-basic-line-ucnkbj?file=src%2Fapp%2Fapp.component.ts
- Modificación Gráfico 2d a 3d : https://www.eduforbetterment.com/3d-pie-and-donut-chart-in-angular-using-highchart/
-
Cifrado Token (CriptoJs) y Secure Local Storage
- Guía de Uso : https://rupesh94.medium.com/how-to-encrypt-localstorage-data-in-angular-270ebcbc1435
- Instalación Secure Local Storage : https://www.npmjs.com/package/secure-web-storage?activeTab=readme
- Instalacion CryptoJs : https://www.npmjs.com/package/crypto-js
Ver
(Esta Documentación que Desarrollé es para la Creación, Configuración, Posibles Errores, Despliegue, etc de la Aplicación con Angular, Firebase y Bootstrap. Recomiendo Leerla y Realizar todo paso a paso como se indica en la misma).
(Primeramente deberás tener instalado VS Code, configurado a gusto y saber/manejar de Forma Básica una CLI(Terminal-Interfaz de Línea de Comandos o como se le quiera decir. Te recomiendo que consideres la CLI Bash/Shell de Linux)).
- Para usar angular se necesita instalar Node.js.
- --> Descarga de Node.js (https://nodejs.org/en/)
- Abrír el Archivo Descargado e Instalar(Siguiente y Siguiente...).
- Angular Depende del 'npm package manager' de Node.js, cuando se descarga este, viene todo incluido.
- Comprobamos la Instalación de Angular desde una CLI.
- --> Abrir el cmd en Windows, bash-shell en Linux, o terminal en VS Code
- --> escribir
npm -v
. - --> Si no surgió ningún error te debería aparecer la Versión de Node.js, ya está instalado Node.js
- Teniendo Instalado el Sistema de Gestión de Angular en Nuestra Computadora, trabajaremos todo desde la CLI
- Abrir el cmd en Windows, bash-shell en Linux, o terminal en VS Code y escribir
npm install -g @angular/cli
. - Si se instalo correctamente la cli de Angular, escribiendo
ng help
se debería poder visualizar la lista de comandos y la versión.(Paciencia porque las ejecuciones de angular son lerdas).
(Este es uno de los pasos más tediosos ya que para la creación de una App en Angular viene intrínsico el proceso de construcción de Paquetes, creación de Módulos, Deploy de la App en el Servidor de Angular, etc).
- Primeramente deberás ubicarte en la carpeta que deseas construir la app con Angular.
- --> En mi caso crearé la app en mi ruta ANGULAR/Proyectos2021
- --> Abrimos una Nueva Terminal en VS Code y
- --> Escribimos
ng new 'nombreDelProyectoSinComillasTodoSeguido'
en mi casong new 'crudAngularFirebaseBootstrap'
- --> Seguidamente nos pregunta si queremos agregar una routing, escribimos yes o y
- --> Ahora cual Lenguaje de Maquetación queremos, elegimos CSS.
- --> Esperamos a que se cree el Proyecto(este paso lleva tiempo).
- Nos posicionamos sobre la carpeta creada
cd crudAngularFirebaseBootstrap
- --> Escribimos por consola
ng serve --open
- --> Si nos preguntan algo escribimos yes o y
- --> El último paso suele tardar un poco
- --> Si se abre el navegador con la página de inicio de Angular está todo Correcto.
- --> Escribimos por consola
( Bootstrap es un Framework Web que nos permite realizar aplicaciones de forma más rápidas y con estructuras modernas. Para este caso no vamos a instalar los paquetes de bootstrap, sino incluir CDN's, osea linkear servidores de boostrap para trabajar con sus librerías )
- Nos dirijimos al
index.html
- Incluimos la hoja de estilo dentro del head
- Código en la Página oficial https://getbootstrap.com/docs/5.1/getting-started/introduction/ o acá..
<!--CSS BOOTSTRAP-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
- Guardamos cambios (Ctrl+s)
- Notar que para Javascript se utiliza junto con la librería Popper
- Bootstrap nos proporciona un CDN con todo incluido
- Incluimos el CDN dentro del body
- Código en la Página Oficial https://getbootstrap.com/docs/5.1/getting-started/introduction/ o acá..
<!--JS Bootstrap-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
- Guardamos cambios (Ctrl+s)
- Si visualizas nuevamente la aplicación se podrá notar la diferencia de tamaños y colores, tenemos implementado Bootstrap
(Todos los componentes y Módulos de Angular están dentro de sus respectivos directorios o carpetas(en este caso el directorio es app, que a su vez es el módulo padre), vamos a realizar lo mismo con Boostrap , crearemos los componentes y módulos y trabajaremos de forma modularizada, respetando el Patrón de Angular)
- Abrimos una nueva terminal
- --> View -> Terminal
- Nos posicionamos sobre el proyecto
- --> Escribimos
cd crud AngularFirebaseBootstrap
- --> Escribimos
- Creamos el Nuevo Componente modularizado
- --> Escribimos
ng generate component components/navbar --module app
ong g c components/navbar --module app
- --> Escribimos
- Si desplegas componentes, se debería haber generado el componente, junto con sus archivos
- Ahora creamos el módulo interno de configuración del navbar
- --> Escribimos
ng generate module components/navbar --module app
ong g m components/navbar --module app
- --> Escribimos
- Vamos a incluir el código html de ejemplo de la página de bootstrap en el
navbar.component.html
(app/navbar/navbar.component.html) - Voy a implementar un Navbar de tipo Offcanvas que se despliegua al costado de la pantalla.
- Código https://getbootstrap.com/docs/5.1/components/navbar/
<nav class="navbar navbar-light bg-light fixed-top">
<div class="container-fluid">
<a class="navbar-brand" href="#">Offcanvas navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasNavbar" aria-labelledby="offcanvasNavbarLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasNavbarLabel">Offcanvas</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav justify-content-end flex-grow-1 pe-3">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="offcanvasNavbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu" aria-labelledby="offcanvasNavbarDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</div>
</nav>
- Seguidamente vamos a comprobar si el componente creado se ha importado dentro de
app.module.ts
- Nos dirigimos al archivo (app/app.module.ts)
- Deberías tener el siguiente código indicando que tenemos el componente importado correctamente
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NavbarComponent } from './components/navbar/navbar.component';
import { NavbarModule } from './components/navbar/navbar.module';
@NgModule({
declarations: [
AppComponent,
NavbarComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
NavbarModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
- Seguidamente vamos a incluir el código html del componente navbar dentro del componente app, especificamente dentro de
app.component.html
- Nos dirijimos a app.component.html(app/app.component.html) y escribimos
<div>
<app-navbar></app-navbar>
</div>
- Guardamos (Ctrl + s )
- Levantamos el Servidor
ng server
desde terminal - Visualizamos el contenido.
- Abrimos una nueva terminal
- Nos posicionamos sobre el proyecto
- Creamos el Nuevo Componente modularizado
- --> Escribimos
ng generate component components/carousel --module app
ong g c components/carousel --module app
- --> Escribimos
- Si desplegas componentes, se debería haber generado el componente, junto con sus archivos
- Ahora creamos el módulo interno de configuración del carousel
- --> Escribimos
ng generate module components/carousel --module app
ong g m components/carousel --module app
- --> Escribimos
- Vamos a incluir el código html de ejemplo de la página de bootstrap en el
carousel.component.html
(app/carousel/carousel.component.html) - Voy a implementar un Carousel de tipo Dark variant
- Voy a incluir algunas rutas a imagenes de internet y cambiar algunos colores para que se visualize correctamente el carousel
- Código https://getbootstrap.com/docs/5.1/components/carousel/
<section>
<div id="carouselExampleDark" class="carousel carousel-ligth slide" data-bs-ride="carousel">
<div class="carousel-indicators">
<button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
<button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="1" aria-label="Slide 2"></button>
<button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="2" aria-label="Slide 3"></button>
</div>
<div class="carousel-inner text-white">
<div class="carousel-item active" data-bs-interval="10000">
<img src="https://www.aawishkar.tech/images/banner.jpg" class="d-block w-100" alt="...">
<div class="carousel-caption d-none d-md-block">
<h5>First slide label</h5>
<p>Some representative placeholder content for the first slide.</p>
</div>
</div>
<div class="carousel-item" data-bs-interval="2000">
<img src="https://images7.alphacoders.com/447/447880.jpg" class="d-block w-100" alt="...">
<div class="carousel-caption d-none d-md-block">
<h5>Second slide label</h5>
<p>Some representative placeholder content for the second slide.</p>
</div>
</div>
<div class="carousel-item">
<img src="https://www.wallpapertip.com/wmimgs/16-165025_electronics-electronics-wallpaper-hd.jpg" class="d-block w-100" alt="...">
<div class="carousel-caption d-none d-md-block">
<h5>Third slide label</h5>
<p>Some representative placeholder content for the third slide.</p>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleDark" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleDark" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</section>
- Seguidamente vamos a comprobar si el componente creado se ha importado dentro de
app.module.ts
- Nos dirigimos al archivo (app/app.module.ts)
- Deberías tener el siguiente código indicando que tenemos el componente importado correctamente
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NavbarComponent } from './components/navbar/navbar.component';
import { NavbarModule } from './components/navbar/navbar.module';
import { CarouselComponent } from './components/carousel/carousel.component';
import { CarouselModule } from './components/carousel/carousel.module';
@NgModule({
declarations: [
AppComponent,
NavbarComponent,
CarouselComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
NavbarModule,
CarouselModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
- Seguidamente vamos a incluir el código html del componente carousel dentro del componente app, especificamente dentro de
app.component.html
- Nos dirijimos a app.component.html(app/app.component.html) y escribimos
<div>
<app-carousel></app-carousel>
</div>
- Guardamos (Ctrl + s )
- Levantamos el Servidor
ng server
desde terminal - Visualizamos el contenido.
- Descargar imágenes e iconos a gusto, en mi caso de electrónica
- Ted recomiendo la página https://www.flaticon.es/iconos-gratis/electronica
- Creamos un directorio raiz dentro de
assets
llamado images(src/assets/images) - Copiamos todas las imágenes descargadas al directorio images
- Incluimos el icono deseado como representación de la tienda y nombre dentro de
navbar.component.html
- Porción de Código
<header>
<div>
<img src="assets/images/elect02.png" alt="" width="40" height="40" class="d-inline-block align-text-top "> ElectroThings
</div>
</header>
- Nos dirigimos al index.html y en title cambiamos el titulo de la app
- Para cambiar el icono de la app, linkear la imagen descargada desde el
<link rel="icon">
- Porción de Código
<head>
<meta charset="utf-8">
<title>ElectroThings</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="assets/images/elect02.png">
</head>
(Mas allá que implementemos un esplendido framework como bootstrap, no podemos dejar de lado css, ya que nos ayuda a ahorrar lineas spaghettis en el html).
- Dentro del navbar.component.css vamos a implementar el maquetado para este componente.
- Por ahora establecemos el color de texto en blanco y cambiamos el light por el dark dentro del navbar
- Código
header {
color: white;
}
img {
padding-right: 2px;
}
div.collapse {
margin-left: 15px;
padding: 5px;
}
(Nuestra Aplicación tendrá diversas páginas en las cuáles crearemos para el listado de los componentes electrónicos, agregar, modificar, etc).
- Vamos a generar un módulo con sus componentes indicando también la ruta del mismo que utilizaremos para la página web deseada. El mismo lo vamos a crear dentro de una nueva ruta (pages/electronica/listado-componentes).
- El comando completo sería
ng g m pages/electronica/listado-componentes --module app --route listado-componentes
- Abris una nueva terminal y escribir el comando anterior (en mi caso)
- Vamos a generar un módulo con sus componentes indicando también la ruta del mismo que utilizaremos para la página web deseada. El mismo lo vamos a crear dentro de una nueva ruta (pages/electronica/detalles-componentes).
- El comando completo sería
ng g m pages/electronica/detalles-componentes --module app --route detalles-componentes
- Abris una nueva terminal y escribir el comando anterior (en mi caso)
- Vamos a generar un módulo con sus componentes indicando también la ruta del mismo que utilizaremos para la página web deseada. El mismo lo vamos a crear dentro de una nueva ruta (pages/electronica/agregar-componentes).
- El comando completo sería
ng g m pages/electronica/agregar-componentes --module app --route agregar-componentes
- Abris una nueva terminal y escribir el comando anterior (en mi caso)
- Vamos a generar un módulo con sus componentes indicando también la ruta del mismo que utilizaremos para la página web deseada. El mismo lo vamos a crear dentro de una nueva ruta (pages/electronica/editar-componentes).
- El comando completo sería
ng g m pages/electronica/editar-componentes --module app --route editar-componentes
- Abris una nueva terminal y escribir el comando anterior (en mi caso)
- Vamos a generar un módulo con sus componentes indicando también la ruta del mismo que utilizaremos para la página web deseada. El mismo lo vamos a crear dentro de una nueva ruta (pages/utilidades/ayuda).
- El comando completo sería
ng g m pages/utilidades/ayuda --module app --route ayuda
- Abris una nueva terminal y escribir el comando anterior (en mi caso)
(Declarar las rutas con directivas en angular se consideran buenas prácticas, ya que podremos controlar los errores que pudiesen surgir).
- Primeramente hay que incluir la Directiva
<router-outlet></router-outlet>
dentro deapp.component.html
, por qué sino no se establece el ruteo de forma dinámica, osea no se van a mostrar las páginas creadas.
<div>
<app-navbar></app-navbar>
<router-outlet></router-outlet>
</div>
- Ahora nos dirigimos al
navbar.component.html
y allí modificamos los nav-item agregando las directivas de enlaces[routerLink] = "['/nombrePagina']"
indicando las páginas de redireccionamiento - Vamos a modificar nuestro Offcanvas navbar a gusto, cambiamos los fondos, agregamos iconos, cambiamos los nombres, etc
- Código
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container-fluid">
<!--Icono-->
<div>
<img src="assets/images/elect02.png" alt="" width="40" height="40" class="d-inline-block align-text-top "> ElectroThings
</div>
<!--Fin Icono-->
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasNavbar" aria-labelledby="offcanvasNavbarLabel">
<!--Boton Close-->
<div class="offcanvas-header bg-dark">
<h5 class="offcanvas-title" id="offcanvasNavbarLabel"><img src="assets/images/elect02.png" alt="" width="40" height="40" class="d-inline-block align-text-top "> ElectroThings</h5>
<button type="button" class="btn-close bg-white text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<!--Fin Boton Close-->
<div class="offcanvas-body bg-dark">
<ul class="navbar-nav">
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/']">Inicio</a>
</li>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/listado-componentes']">Listado de Componentes</a>
</li>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/agregar-componentes']">Agregar Componentes</a>
</li>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/editar-componentes']">Editar Componentes</a>
</li>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/ayuda']">Ayuda</a>
</li>
</ul>
</div>
</div>
</div>
</nav>
</header>
(Un servicio Angular es un objeto sin estado y proporciona algunas funciones muy útiles. Estas funciones se pueden invocar desde cualquier componente de Angular, como Controladores, Directivas, etc. Esto ayuda a dividir la aplicación web en unidades lógicas pequeñas y diferentes que se pueden reutilizar.).
- Vamos a generar el servicio dentro de la carpeta de electronica y el mismo se llamara electronica.service (pages/electronica/electronica.service).
- El comando completo sería
ng g s pages/electronica/electronica
- Abris una nueva terminal y escribir el comando anterior (en mi caso)
- Se tendria que haber generado el archivo
electronica.service.ts
- Copiamos la estructura base de la tabla de bootstrap https://getbootstrap.com/docs/5.1/content/tables/ y la pegamos en el
listado-componentes.component.html
dentro del modulolistado-componentes
. - Voy a cambiar la variante de la tabla a tipo hover, también los nombres, columnas, agregar botones, colores, etc.
- También voy a agregar iconos de bootstrap
(https://icons.getbootstrap.com/)
para la visualizacion, la edición y la eliminación de los productos del listado
- Vamos a replicar el listado de productos 4 veces, usando la directiva de angular
*ngFor
, esta directiva nos permite generar muchos elementos HTML repetidos a partir de un recorrido de un arreglo de datos.
<!--Replicamos 4 veces los productos e iconos-->
<tr *ngFor=" let producto of [0,1,2,3,4]">
<th scope="row">1</th>
<td>Módulo WIFI MCU-ESP32</td>
<td>MCU-65788</td>
<td>1600</td>
- Necesitamos funciones que nos permitan eliminar, mostrar y modificar los PRODUCTOS que se muestran en el listado, estas funciones las vamos a usar con eventos posteriormente.
- Nos dirigimos a
listado-componentes.component.ts
- Vamos a pasarle la clase Route en el constructor, esta clase es la encargada de gestionar las rutas de nuestras paginas web creadas. Importar dichos módulos
- Vamos a utilizar la propiedad llamada
state
dentro y fuera de los métodos que desarrollemos, esta propiedad nos permite trabajar con el objeto completo, dicha propiedad deberá ser implementada en cada una de las siguientes funciones. - Para usar dicha propiedad debemos declarar un objeto de tipo NavigationExtras importando la interfaz correspondiente y pasandole un estado
- Código de la Propiedad..
navigationExtras : NavigationExtras = {
state : {
value:null
};
ATENTI
, si se tiene una configuración estricta de TypeScript surgirá un error en este paso, ya que se está declarando la propiedad como nula, hay que dirigirnos al archivotsconfig.json
y dentro delcompilerOptions
cambiar el paramnetro"strict":true
a"strict":false
- Por Último vamos a crear las funciones. Las mismas se llamaran
editarProducto
,eliminarProducto
ymostrarProducto
.
- Este Método va a recibir un producto en su argumento
- Luego, por el momento , en el cuerpo del método vamos a indicar con un alert que simplemente nos diga que el producto ha sido borrado..
- Código Snippet..
// Eliminar Productos
eliminarProducto(producto : any): void{
alert('El Producto ha sido Eliminado');
}
- Este Método va a recibir un producto en su argumento
- En el cuerpo del método vamos a pasarle la ruta definida cuando creamos los componentes de las paginas creadas anteriormente que va a mostrar en detalle dicho producto. Además vamos a usar la propiedad creada
navigationExtras
haciendo referencia al valor delstate
para trabajar con el objeto en sí. En el segundo parametro delrouter.navigate
vamos a pasarle además el estado de la propiedad creada - Código Snippet..
// Editar Productos
editarProducto(producto : any): void{
this.navigationExtras.state.value = producto;
this.router.navigate(['editar-componentes'] , this.navigationExtras);
}
- Este Método va a recibir un producto en su argumento
- En el cuerpo del método vamos a pasarle la ruta definida cuando creamos los componentes de las paginas creadas anteriormente que va a mostrar en detalle dicho producto. Además vamos a usar la propiedad creada
navigationExtras
haciendo referencia al valor delstate
para trabajar con el objeto en sí. En el segundo parametro delrouter.navigate
vamos a pasarle además el estado de la propiedad creada - Código Snippet..
// Mostrar Productos
detallesProducto(producto : any): void{
this.navigationExtras.state.value = producto;
this.router.navigate(['detalles-componentes'] , this.navigationExtras);
}
- Código Completo para
listado-componentes.component.ts
..
import { Component, OnInit } from '@angular/core';
import { NavigationExtras, Router } from '@angular/router';
@Component({
selector: 'app-listado-componentes',
templateUrl: './listado-componentes.component.html',
styleUrls: ['./listado-componentes.component.css']
})
export class ListadoComponentesComponent implements OnInit {
navigationExtras : NavigationExtras = {
state : {
value :null
}
};
constructor(private router: Router) { }
ngOnInit(): void {
}
// Métodos CRUD para los Componentes Electrónicos
// Mostrar Productos
detallesProducto(producto : any): void{
this.navigationExtras.state.value = producto;
this.router.navigate(['detalles-componentes'] , this.navigationExtras);
}
// Editar Productos
editarProducto(producto : any): void{
this.navigationExtras.state.value = producto;
this.router.navigate(['editar-componentes'] , this.navigationExtras);
}
// Eliminar Productos
eliminarProducto(producto : any): void{
alert('El Producto ha sido Eliminado');
}
}
-
El enlace de Eventos escucha los eventos de click en el botón y llama al método indicado cada vez que se produce un click
-
Para poder implementar este evento se deben haber creado previamente las funciones correspondientes para que realizen las acciones de tipo CRUD básicas (editar, eliminar, agregar elementos), como se indica paso a paso en los items anteriores.
-
Estas funciones se van a agregar dentro de cada boton correspondiente para que realice la acción deseada.
-
Código..
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Nombre</th>
<th scope="col">Código</th>
<th scope="col">Precio</th>
<th class="d-none d-sm-block" scope="col">Opciones</th>
</tr>
</thead>
<tbody>
<!--Replicamos 4 veces los productos e iconos-->
<tr *ngFor=" let producto of [0,1,2,3,4]">
<th scope="row">1</th>
<td>Módulo WIFI MCU-ESP32</td>
<td>MCU-65788</td>
<td>1600</td>
<!--En caso de moviles ocultamos -->
<td class="btn-group d-none d-sm-block" role="group">
<button class="btn btn-primary border-light alert-link m-1" (click)="detallesProducto(producto)">
<!--Icono Visualizar Producto-->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrows-fullscreen" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707zm4.344 0a.5.5 0 0 1 .707 0l4.096 4.096V11.5a.5.5 0 1 1 1 0v3.975a.5.5 0 0 1-.5.5H11.5a.5.5 0 0 1 0-1h2.768l-4.096-4.096a.5.5 0 0 1 0-.707zm0-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707zm-4.344 0a.5.5 0 0 1-.707 0L1.025 1.732V4.5a.5.5 0 0 1-1 0V.525a.5.5 0 0 1 .5-.5H4.5a.5.5 0 0 1 0 1H1.732l4.096 4.096a.5.5 0 0 1 0 .707z"/>
</svg>
<!--Fin Icono Visualizar Producto-->
</button>
<button class="btn btn-warning border-light alert-link m-1 " (click)="editarProducto(producto)">
<!--Icono Editar Producto-->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
</svg>
<!--Fin Icono Editar Producto-->
</button>
<button class="btn btn-danger border-light alert-link m-1 " (click)="eliminarProducto(producto)">
<!--Icono Eliminar Producto-->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>
<!--Fin Icono Eliminar Producto-->
</button>
</td>
</tr>
</tbody>
</table>
<div class="container">
<div class="row justify-content-center">
<div class="col-2">
<button class="btn btn-outline-dark border-dark alert-link m-2 ">Regresar
<!--Icono Regresar Inicio-->
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-reply-fill" viewBox="0 0 16 16">
<path d="M5.921 11.9 1.353 8.62a.719.719 0 0 1 0-1.238L5.921 4.1A.716.716 0 0 1 7 4.719V6c1.5 0 6 0 7 8-2.5-4.5-7-4-7-4v1.281c0 .56-.606.898-1.079.62z"/>
</svg>
<!--Fin Icono Regresar Inicio-->
</button>
</div>
<div class="col-2">
<button class="btn btn-outline-dark border-dark alert-link m-2 ">Actualizar
<!--Icono Actualizar Listado-->
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-repeat" viewBox="0 0 16 16">
<path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/>
<path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/>
</svg>
<!--Fin Icono Actualizar Listado-->
</button>
</div>
</div>
</div>
</div>
-
Una vez definidos los métodos CRUD vamos a capturar los objetos que se pasen al
state
cuando se haga click en el icono de editar. -
Vamos a trabajar las Navegaciones y estados en
editar-componentes.component.ts
-
Nos dirigimos a
editar-componentes.component.ts
-
Dentro de la clase EditarComponentesComponent, fuera del constructor declaramos una variable llmada
valorProducto
del objeto como nulo. Dentro del constructor indicamos que la variable-propiedadvalorProducto
tendrá la propiedad de tomar el estado actual del objeto. Osea que nos muestre el valor de ese objeto . -
Una vez allí, dentro del constructor, inyectamos el
router
definiendolo en su argumento, dentro de este creamos una variable-propiedad (const navigacionActual
) que nos traiga ese objeto con el métodogetCurrentNavidation()
a través de la ruta pasada. -
Los signos de interrogación se indican ya que no es necesario pasarle sus valores.
-
Código Completo..
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-editar-componentes',
templateUrl: './editar-componentes.component.html',
styleUrls: ['./editar-componentes.component.css']
})
export class EditarComponentesComponent implements OnInit {
valorProducto = null
constructor(private router : Router) {
const navigacionActual = this.router.getCurrentNavigation();
this.valorProducto = navigacionActual?.extras?.state;
}
ngOnInit(): void {
}
}
- Por Último testeamos el valor del objeto que se obtiene al hacer click sobre el boton de editar.
- Nos dirigimos a
editar-componentes.component.html
e indicamos con interpolación el valor del producto, trabajamos con json. - Código Snippet..
<p>editar-componentes works!</p>
{{ valorProducto | json }}
- Una vez definidos los métodos CRUD vamos a capturar los objetos que se pasen al
state
cuando se haga click en el icono de detalles. - Vamos a trabajar las Navegaciones y estados en
detalles-componentes.component.ts
- Nos dirigimos a
detalles-componentes.component.ts
- Dentro de la clase DetallesComponentesComponent, fuera del constructor declaramos una variable llamada
valorProducto
del objeto como nulo. Dentro del constructor indicamos que la variable-propiedadvalorProducto
tendrá la propiedad de tomar el estado actual del objeto. Osea que nos muestre el valor de ese objeto . - Una vez allí, dentro del constructor, inyectamos el
router
definiendolo en el argumento del constructor, dentro de este creamos una variable-propiedad (const navigacionActual
) que nos traiga ese objeto con el métodogetCurrentNavidation()
a través de la ruta pasada. - Los signos de interrogación se indican ya que no es necesario pasarle sus valores.
- Vamos a crear una funcion para que nos regrese al listado de componentes cuando estemos en el detalle de un solo componente, la funcion se va a llamar
regresarListadoComponentes()
- Vamos a reutilizar las funciones
editarProducto()
yeliminarProducto()
que declaramos en ellistado-componentes.component.ts
, para las operaciones de este producto. La diferencia acá es que no necesitamos pasarle el producto clickeado en el argumento de la funcion ya que lo recuperamos con elgetCurrentNavigation
, por ende en los estados de la funcion le pasamos la variable declaradavalorProducto
- Importante declarar el navigationExtras e importar su módulo
- Código Completo..
import { Component, OnInit } from '@angular/core';
import { NavigationExtras, Router } from '@angular/router';
@Component({
selector: 'app-detalles-componentes',
templateUrl: './detalles-componentes.component.html',
styleUrls: ['./detalles-componentes.component.css']
})
export class DetallesComponentesComponent implements OnInit {
navigationExtras : NavigationExtras = {
state : {
value :null
}
};
valorProducto = null;
constructor(private router: Router) {
const navegacionActual = this.router.getCurrentNavigation();
this.valorProducto = navegacionActual?.extras?.state;
}
ngOnInit(): void {
}
//Regresar Listado Productos
regresarListadoProductos():void{
this.router.navigate(['listado-componentes']);
}
// Editar Productos
editarProducto(): void{
this.navigationExtras.state.value = this.valorProducto;
this.router.navigate(['editar-componentes'] , this.navigationExtras);
}
// Eliminar Productos
eliminarProducto(): void{
alert('El Producto ha sido Eliminado');
}
}
- Por Último testeamos el valor del objeto que se obtiene al hacer click sobre el boton de detalles.
- Nos dirigimos a
detalles-componentes.component.html
e indicamos con interpolación el valor del producto, trabajamos con json. - Código Snippet..
<p>detalles-componentes works!</p>
{{ valorProducto | json }}
- En esta página se alojará el detalle de cada componente una vez que el usuario haga click sobre el icono de detalles.
- La Maquetación de la Página es
detalles-componentes.component.html
- Voy a crear un Card para el Producto con su foto, detalle, etc y otro Card para el detalle del producto con sus botones y descripcion. La idea es que ambas cards sean responsives.
- Una vez que hemos declarado las funciones en el
detalles-componentes.component.ts
, vamos a pasarles los eventos a los botones y cuando se haga click se dispare las funciones realizadas anteriormente. * En el boton de regresar declaramos la funcion click para que se dispare dicho evento y nos muestre el alert..
<button class="btn btn-danger border-dark alert-link m-1 " (click)="regresarListadoProductos()">
- En el boton de eliminar declaramos la funcion click para que se dispare dicho evento y nos muestre el alert..
<button class="btn btn-danger border-dark alert-link m-1 " (click)="eliminarProducto()">
- En el boton de editar declaramos la funcion click para que se dispare dicho evento
<button class="btn btn-danger border-dark alert-link m-1 " (click)="editarProducto()">
- Código completo de
detalles-componentes.component.html
..
<div class="container m-2">
<div class="row justify-content-start">
<!--CARD PRODUCTO-->
<div class="col-md-5 col-sm-12">
<div class="card bg-opacity-10 bg-secondary" style="max-width: 540px;">
<div class="row g-0 ">
<div class="col-md-4">
<img src="assets/images/esp32.jpg" class="card-img-top " alt="...">
</div>
<div class="col-md-8 ">
<div class="card-body ">
<h5 class="card-title bg-gradient bg-opacity-10 bg-dark text-center">Módulo Wifi Mcu Esp32</h5>
<p class="card-text">Incluyen puerto de conexión microUSB para alimentación y conector JST para alimentación de la placa. Y se pueden programar desde el IDE de Arduino..</p>
</div>
<div class="card-body ">
<a href="https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf" class="card-link text-dark">Datasheet</a>
<a href="https://www.espressif.com/sitproyectos%20esp32es/default/files/documentation/esp32_datasheet_en.pdf" class="card-link text-dark">Proyectos</a>
<a href="https://www.espressif.com/sitproyectos%20esp32es/default/files/documentation/esp32_datasheet_en.pdf" class="card-link text-dark">Más Info</a>
</div>
</div>
</div>
</div>
</div>
<!--FIN CARD PRODUCTO-->
<!--CARD DETALLES PRODUCTO-->
<div class="col-md-7 col-sm-12">
<div class="bg-opacity-10 bg-dark ">
<hr>
<div class="card-body text-center">
<div class="text-center ">
<h5 class="text-underline">DETALLES PRODUCTO</h5>
</div>
<hr>
<ul class=" m-2 p-2 text-center list-group list-group-flush list-group-horizontal-lg list-group-horizontal-md input-group ">
<li class="list-group-item "><strong>ID</strong>
<p>1</p>
</li>
<li class="list-group-item "><strong>Nombre</strong>
<p>Módulo Wifi Mcu Esp32
</p>
</li>
<li class="list-group-item"><strong>Código</strong>
<p>MCU-65788</p>
</li>
<li class="list-group-item"><strong>Precio</strong>
<p>1600</p>
</li>
</ul>
</div>
</div>
<!--BOTONES-->
<div class="container col-sm-12 bg-opacity-75 bg-dark p-1">
<div class="row justify-content-center">
<div class="col-md-2 col-sm-2">
<button class="btn btn-primary border-dark alert-link m-1 " (click)="regresarListadoProductos()">
<!--Icono Regresar-->
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-return-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M14.5 1.5a.5.5 0 0 1 .5.5v4.8a2.5 2.5 0 0 1-2.5 2.5H2.707l3.347 3.346a.5.5 0 0 1-.708.708l-4.2-4.2a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 8.3H12.5A1.5 1.5 0 0 0 14 6.8V2a.5.5 0 0 1 .5-.5z"/>
</svg>
<!--FIN Icono Regresar-->
</button>
</div>
<div class="col-md-2 col-sm-2">
<button class="btn btn-warning border-dark alert-link m-1 " (click)="editarProducto()">
<!--Icono Editar Producto-->
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
</svg>
<!--Fin Icono Editar Producto-->
</button>
</div>
<div class="col-md-2 col-sm-2">
<button class="btn btn-danger border-dark alert-link m-1 " (click)="eliminarProducto()">
<!--Icono Eliminar Producto-->
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>
<!--Fin Icono Eliminar Producto-->
</button>
</div>
<div class="col-md-2 col-sm-2">
<button onClick="window.location.reload()" class="btn btn-secondary border-dark alert-link m-1 ">
<!--Icono Actualizar Listado-->
<svg xmlns="http://www.w3.org/2000/svg " width="20 " height="20 " fill="currentColor " class="bi bi-arrow-repeat " viewBox="0 0 16 16 ">
<path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z "/>
<path fill-rule="evenodd " d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z "/>
</svg>
<!--Fin Icono Actualizar Listado-->
</button>
</div>
</div>
</div>
<!--FIN BOTONES-->
{{valorProducto | json}}
</div>
<!-- CARD FIN DETALLES PRODUCTO-->
</div>
(Esta Página contendrá el formulario para editar el componente seleccionado de la lista de componentes de Electrónica)
- git init
- git add *
- git commit -m "agrega un comentario entre comillas"
5)Le indicamos a git donde se va a almacenar nuestro proyecto(fijate en tu repositorio de github cual es el enlace de tu proyecto(esta en code)).
- git remote add origin https://github.com/andresWeitzel/AppTiendaElectronica_Angular_Firebase_Bootstrap
- git push -u origin master
- git status
- git add *
- git commit -m "Tu commit entre comillas"
4)Sincronizamos y traemos todos los cambios del repositorio remoto a la rama en la que estemos trabajando actualmente.
Desconozco porqué tengo que ejecutar este comando, supongo que será porque no estoy trabajando con branchs en mi proyecto, el main por defecto de gitHub ahora es mi master(Yo realicé esa modificación para mejor visualización)).
- npm i netlify-cli
- netlify login
- netlify status
- netlify --version
- ng build --prod
- netlify deploy --prod