Ticker

6/recent/ticker-posts

Creando una Aplicación Web en Angular con integración a una API RESTful

En este tutorial práctico desarrollaremos una aplicación web con Angular 14, TypeScript y Bootstrap e integraremos a nuestra API RESTful desarrollada en Spring Boot, en específico, la aplicación web es con relación a los métodos CRUD; asimismo, para el almacenamiento de datos haremo uso de la base de datos PostgreSQL.


Requisitos:

  1. Spring Initializr.
  2. Java 17.
  3. Maven 3.8.6.
  4. IntelliJ IDEA Community Edition.
  5. Visual Studio Code y pgAdmin 4.
  6. Angular 14, Angular CLI y Node.JS.
  7. TypeScript y Bootstrap.


Lo que veremos en este tutorial:

  1. Angular y Angular CLI.
  2. Crear el proyecto Angular.
  3. Crear los Componentes.
  4. Crear el Servicio.
  5. Importar los módulos.
  6. Implementar las rutas.
  7. Implementar la interfaz.
  8. Implementar el servicio.
  9. Implementar los componentes.
  10. Conclusiones y Referencias.


1. Angular y Angular CLI.

Angular es un Framework basado en JavaScript de código abierto escrito en TypeScript; su principal objetivo es desarrollar aplicaciones de una sola página - Single Page Application (SPA) y Progressive Web App (PWA), tanto para versiones móviles como de escritorio. Google es el propietario y encarga del mantenimiento y constantes actualizaciones de mejoras para este Framework.

Angular CLI es el Command Line Interface (interfaz en línea de comandos traducidos al español), desarrollado por Angular, este CLI permite inicializar, desarrollar, estructurar y mantener aplicaciones de Angular directamente desde la terminal; es decir, permite  crear el árbol de directorios y archivos necesarios (scaffolding) para un nuevo proyecto Angular, esto se hace a través de una linea de comandos.

Todos los objetos se crearán desde la terminal de Angular CLI según los comandos correspondientes.

2. Crear el proyecto Angular.

El proyecto se creará haciendo uso del siguiente comando:
ng new frontend-crud-angular

Seguidamente acceder al directorio (frontend-crud-angular) principal del proyecto que se acaba de crear:
cd frontend-crud-angular

3. Crear los Componentes.

Al crear los componentes que involucran en el proyecto frontend de Agular se describen como modulos que involucran nuestro proyecto.

Crearmos el primer componente de nombre "list":
ng g c components/list

Crearmos el segundo componente de nombre "add"
ng g c components/add

Crearmos el tercer componente de nombre "edit"
ng g c components/edit


4. Crear el Servicio.

Creamos el servicio de nombre "asignatura":
ng g s services/asignatura

5. Importar los módulos.

Ahora importamos e importamos los modulos, teniendo en referencias a todos los componentes creados en el punto 3; abrir el archivo app.module.ts e importar los componentes:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ListarComponent } from './components/listar/listar.component';
import { AddComponent } from './components/add/add.component';
import { EditComponent } from './components/edit/edit.component';
import { DeleteComponent } from './components/delete/delete.component';
import { FormsModule } from '@angular/forms';
import { HttpClientModule} from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
    ListarComponent,
    AddComponent,
    EditComponent,
    DeleteComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


6. Implementar las rutas.

Ahora importamos e implementamos las rutas; abrir el archivo app-routing.module.ts y agregar los path:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AddComponent } from './components/add/add.component';
import { EditComponent } from './components/edit/edit.component';
import { ListarComponent } from './components/listar/listar.component';

const routes: Routes = [
  {path: '', redirectTo: 'list', pathMatch: 'full'},
  /* rutear los componentes listar, editar por código y agregar registros */
  {path: 'list', component: ListarComponent},
  {path: 'edit/:cod', component: EditComponent},
  {path: 'add', component: AddComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }


7. Implementar la interfaz.

Para implementar el modelo Asignatura se debe crear el directorio modelo y seguidamente crear el archivo asignatura.ts, finalmente implementar el modelo:

export interface Asignatura{
    codigo:string;
    nombre:string;
    creditos:string;
    duracion: string;
    contenido:string;
    costo:string;
}


8. Implementar el servicio.

Implementar el servicio en el archivo asignatura.service.ts, se de considerar que la URL del servicio debe esta activo (en ejecución o publicado en un servidor):

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Asignatura } from '../model/asignatura';

@Injectable({
  providedIn: 'root'
})
export class AsignaturaService {

  /* innovar la url del servicio construido en Spring Boot */
  url = 'http://localhost:8085/api/asignatura';
  constructor(private http: HttpClient) { }

  /* método para listar todos los registros de la asignatura */
  getAsignatura(): Observable<any>{
    return this.http.get(this.url);
  }

  /* método para buscar los registros según el id de la asignatura */
  getIdAsignatura(id: string): Observable<any>{
    return this.http.get(this.url+'/'+id);
  }

  /* método para guardar los registros de la asignatura */
  saveAsignatura(asignatura: Asignatura):Observable<any>
  {
    return this.http.post(this.url, asignatura);
  }

  /* método para actualizar los registros según el id de la asignatura */
  editAsignatura(id: string, asignatura: Asignatura):Observable<any>{
    return this.http.put(this.url+'/'+id, asignatura)
  }
  /* método para eliminar los registros según el id de la asignatura */
  deleteAsignatura(id: string):Observable<any>{
    return this.http.delete(this.url+'/'+id);
  }
}


9. Implementar los componentes.

9.1. Implementar el archivo TypeScript de nombre listar.component.ts y archivo HTML de nombre listar.component.html con relación al modelo (componente) "list":

  • TypeScript de nombre listar.component.ts

import { Component, OnInit } from '@angular/core';
import { AsignaturaService } from 'src/app/services/asignatura.service';

@Component({
  selector: 'app-listar',
  templateUrl: './listar.component.html',
  styleUrls: ['./listar.component.css']
})
export class ListarComponent implements OnInit {
 
  list:any=[];  
  constructor(private asignaturaService: AsignaturaService) { }

  ngOnInit(): void {
    this.listAsig();/* Iniciar cargando la lista asignatura */
  }

  /* Método para listar los registros */  
  listAsig()
  {
    /* Referenciar al método getAsignatura() del servicio asignatura */
    this.asignaturaService.getAsignatura().subscribe(
      res=>{
        this.list=res;
        console.log(res);
      },
      err=>console.log(err)
    );
  } 
}


  • HTML de nombre listar.component.html

<div class="container">

    <div class="row">
        <div class="col-sm-12 p-3">
            <button type="button" class="btn btn-success" [routerLink]="['/add']">Agregar</button>
        </div>
        <div class="col-sm-12">

            <div class="table-responsive">
                <table class="table">
                    <thead>
                        <tr>
                            <th scope="col">Nombre</th>
                            <th scope="col">Créditos</th>
                            <th scope="col">Duracion</th>
                            <th scope="col">Contenido</th>
                            <th scope="col">Costo</th>
                            <th scope="col">#</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr *ngFor="let asignatura of list"><!-- listar los registro asignatura -->                            
                            <td>{{asignatura.nombre}}</td>
                            <td>{{asignatura.creditos}}</td>
                            <td>{{asignatura.duracion}}</td>
                            <td>{{asignatura.contenido}}</td>
                            <td>{{asignatura.costo}}</td>
                            <td>
                                <button type="button" class="btn btn-primary btn-sm"
                                    [routerLink]="['/edit/', asignatura.codigo]">Editar</button><!-- Botón Editar -->  
                            </td>
                        </tr>
                    </tbody>
                </table>

            </div>
        </div>
    </div>
</div>
 

  • Interfaz del listar.component.html

Interfaz HTML con relación al listar regitros - listar.component.html




9.2. Implementar el archivo TypeScript de nombre add.component.ts y archivo HTML de nombre add.component.html con relación al modelo (componente) "edit":

  • TypeScript de nombre add.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Asignatura } from 'src/app/model/asignatura';
import { AsignaturaService } from 'src/app/services/asignatura.service';

@Component({
  selector: 'app-add',
  templateUrl: './add.component.html',
  styleUrls: ['./add.component.css']
})
export class AddComponent implements OnInit {

  addAsignatura: Asignatura={codigo:'',nombre:'',creditos:'',duracion:'',contenido:'',costo:''};
  constructor(private asignaturaService: AsignaturaService, private router:Router) { }

  ngOnInit(): void {
  }

  /* método para guardar los registros de la asignatura */
  addAsig(){
    /* invocar el método para guardar los registros de la asignatura */
    this.asignaturaService.saveAsignatura(this.addAsignatura).subscribe(
      res=>{
        console.log(res);
        /* direccionar a la vista list */
        this.router.navigate(['/list']);
      },
      err=>console.log(err)
    )
  }
}


  • HTML de nombre add.component.html

<div class="container">
    <form action="">
        <div class="form-group">
            <label for="curso">Curso</label>
            <input type="text" class="form-control" name="curso" id="curso" [(ngModel)]="addAsignatura.nombre" placeholder="Nombre del curso">            
        </div>
       
        <div class="form-group">
            <label for="creditos">Créditos</label>
            <input type="text" class="form-control" name="creditos" id="creditos" [(ngModel)]="addAsignatura.creditos" placeholder="Cantidad de créditos del curso">
        </div>

        <div class="form-group">
            <label for="duracion">Duración</label>
            <input type="text" class="form-control" name="duracion" id="duracion" [(ngModel)]="addAsignatura.duracion" placeholder="Duración del curso">
        </div>

        <div class="form-group">
            <label for="contenido">Contenido</label>
            <textarea class="form-control" name="contenido" id="contenido" [(ngModel)]="addAsignatura.contenido" rows="3"></textarea>
        </div>

        <div class="input-group mb-3">
            <div class="input-group-prepend">
                <span class="input-group-text">$</span>
            </div>
            <input type="text" class="form-control" name="costo" id="costo" [(ngModel)]="addAsignatura.costo" aria-label="Amount (to the nearest dollar)">
            <div class="input-group-append">
                <span class="input-group-text">.00</span>
            </div>
        </div>
       
        <div>
            <button class="btn btn-primary" (click)="addAsig()">Guardar</button>            
        </div>
    </form>
</div>


  • Interfaz del add.component.html

Interfaz HTML con relación al actualizar regitros - add.component.html




9.3. Implementar el archivo TypeScript de nombre edit.component.ts y archivo HTML de nombre edit.component.html con relación al modelo (componente) "add":

  • TypeScript de nombre edit.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AsignaturaService } from 'src/app/services/asignatura.service';
import { Asignatura } from 'src/app/model/asignatura';

@Component({
  selector: 'app-edit',
  templateUrl: './edit.component.html',
  styleUrls: ['./edit.component.css']
})
export class EditComponent implements OnInit {

  cod:string="";
  editAsignatura: Asignatura={codigo:'',nombre:'',creditos:'',duracion:'',contenido:'',costo:''};
  constructor(
    private asignaturaService: AsignaturaService,
    private activateRouter: ActivatedRoute,
    private router: Router
  ) { }

  /* Iniciar cargando para listar los valores según el id asignatura */
  ngOnInit(): void {
    this.cod = this.activateRouter.snapshot.params.cod;
     /* invocar el método para listar los registro según el id de la asignatura */
    this.asignaturaService.getIdAsignatura(this.cod).subscribe(
      res=>{this.editAsignatura=res},
      err=>console.log(err)            
    );
    console.log(this.cod);
  }

  /* método para editar o actualizar los registros según el id de la asignatura */
  editAsig(){
    /* invocar el método para editar los registro según el id de la asignatura */
    this.asignaturaService.editAsignatura(this.cod, this.editAsignatura).subscribe(
      res=>{  
        /* direccionar a la vista list */      
        this.router.navigate(['/list']);
      },
      err=>console.log(err)
    )
  }
}


  • HTML de nombre edit.component.html

<div class="container">
    <form action="">
        <div class="form-group">
            <label for="curso">Curso</label>
            <input type="text" class="form-control" name="curso" id="curso" [(ngModel)]="editAsignatura.nombre" placeholder="Nombre del curso">            
        </div>
       
        <div class="form-group">
            <label for="creditos">Créditos</label>
            <input type="text" class="form-control" name="creditos" id="creditos" [(ngModel)]="editAsignatura.creditos" placeholder="Cantidad de créditos del curso">
        </div>

        <div class="form-group">
            <label for="duracion">Duración</label>
            <input type="text" class="form-control" name="duracion" id="duracion" [(ngModel)]="editAsignatura.duracion" placeholder="Duración del curso">
        </div>

        <div class="form-group">
            <label for="contenido">Contenido</label>
            <textarea class="form-control" name="contenido" id="contenido" [(ngModel)]="editAsignatura.contenido" rows="3"></textarea>
        </div>

        <div class="input-group mb-3">
            <div class="input-group-prepend">
                <span class="input-group-text">$</span>
            </div>
            <input type="text" class="form-control" name="costo" id="costo" [(ngModel)]="editAsignatura.costo" aria-label="Amount (to the nearest dollar)">
            <div class="input-group-append">
                <span class="input-group-text">.00</span>
            </div>
        </div>
       
        <div>
            <button class="btn btn-primary" (click)="editAsig()">Guardar</button>            
        </div>
    </form>
</div>


  • Interfaz del edit.component.html

Cambiar los registros y clic en el botón Guardar para actualizar los datos.




9.4. Implementar el método eliminar en el archivo TypeScript de nombre listar.component.ts, seguidamente agregar el botón eliminar en el archivo HTML de nombre listar.component.html:

  • TypeScript de nombre listar.component.ts


  /* Método para eliminar el registro según el id de la asignatura */
  deleteAsig(id:string){    
    /* Referenciar al método deleteAsignatura() del servicio asignatura */
    this.asignaturaService.deleteAsignatura(id).subscribe(
      res=>{this.ngOnInit();},
      err=>console.log(err)
    );
  }


  • HTML de nombre listar.component.html 


<button type="button" class="btn btn-danger btn-sm"
(click)="deleteAsig(asignatura.codigo)">Eliminar</button><!-- Botón Eliminar -->  



  • Interfaz con el botón eliminar desde el HTML edit.component.html
Para eliminar un registro, clic en el botón eliminar.



10. Conclusiones y Referencias.

Conclusiones:

  • Se elaboro el proyecto Angular y se implementaron los componentes y métodos necesarios con relación a la aplicación CRUD.
  • Se invoco la URL del Web API construido en Spring Boot


Referencias:


Código disponible en GitHub

Gracias nuevamente 😊 comentarios y apreciaciones son bienvenido, un fuerte abrazo para todos ✌...!!!

Publicar un comentario

0 Comentarios