saltar al contenido
¿Cómo crear una aplicación en App Builder utilizando una API basada en roles?

¿Cómo crear una aplicación en App Builder utilizando una API basada en roles?

En esta guía paso a paso, le mostraremos la forma de crear una aplicación totalmente funcional y personalizable. A los efectos del artículo, utilizaremos código reducido y API basada en roles.

20min de lectura

En este emocionante tutorial, llevaremos tus habilidades al siguiente nivel combinando dos poderosas herramientas: la API que construimos en nuestro tutorial anterior y la plataforma App Builder TM. Al hacerlo, crearemos una aplicación totalmente funcional y personalizable que se puede utilizar en una variedad de plataformas.

App Builder es una poderosa herramienta que permite a los usuarios crear aplicaciones robustas con una experiencia mínima en codificación. Con su interfaz fácil de usar, puede arrastrar y soltar fácilmente diferentes elementos para crear una aplicación pulida y de aspecto profesional en poco tiempo y generar el código para ella en Angular, Blazor o Web Components.

Creación de su primera aplicación en App Builder low-code

Para comenzar, inicie App Builder y seleccione "Crear nueva aplicación". A continuación, ve a la sección "Aplicaciones de muestra" y elige el panel de RRHH como diseño base para tu proyecto. A partir de ahí, puedes ampliar y personalizar el diseño para que se adapte a tus necesidades específicas.

Create new application in App Builder

Al abrir la muestra, notará que ya se han creado varias páginas para usted. Sin embargo, para adaptarse mejor a los requisitos de nuestro proyecto, deberá realizar modificaciones en algunas de estas páginas y crear otras nuevas también.

make changes to your app in App Builder

Ahora, vamos a crear las páginas de inicio de sesión y registro. Vaya a la pestaña "Vistas" y seleccione el icono más para crear una nueva página a la que llamaremos "Registrar página".

create example  login and register pages in App Builder

Para mantener la coherencia, también podemos reutilizar el fondo de la página maestra para la página Registro. Necesitaremos agregar un diseño de columna. Dentro de este diseño, incluiremos un título con el contenido de registro y cinco campos de entrada junto con un botón. Es importante tener en cuenta que todos los campos de entrada deben ser obligatorios y deben tener el tipo adecuado especificado.

Column layout in App Builder

A continuación, podemos crear la pantalla de inicio de sesión. Esta pantalla solo requerirá dos campos de entrada: uno para el correo electrónico y otro para la contraseña. Para simplificar el proceso, podemos duplicar la página de registro y eliminar cualquier elemento innecesario.

Example login page in App Builder

Una vez que se han creado ambas páginas, podemos agregar enlaces a cada página debajo de los botones de envío.

Add links between two pages in App Builder

La página de inicio contará con el panel de control, que mostrará todos los eventos a los que asiste el usuario actual en los componentes de la tarjeta. Si el usuario tiene un rol de administrador, también verá una cuadrícula con todos los eventos de la plataforma, lo que le permitirá realizar operaciones CRUD según sea necesario.

event actions in App Builder

En el futuro, crearemos una página para agregar nuevos eventos. Esta página solo será accesible para los usuarios con un rol de administrador, pero lo cubriremos más adelante en el tutorial. Para cada evento, necesitaremos un título, categoría, correos electrónicos de los usuarios asistentes y la fecha del evento.

create a page for adding new events in App Builder

Además, necesitaremos crear una página similar para cambiar los roles de los usuarios. Al igual que la página del evento, esta función solo será accesible para los administradores. A los efectos de esta demostración, solo admitiremos la concesión de permisos de administrador a otros usuarios.

create a similar page for changing the roles of users in App Builder

Una vez creadas todas nuestras páginas, podemos vincularlas a la barra lateral de navegación.

link thems into the sidebar navigation in App Builder

No es necesario conectar la API manualmente

Afortunadamente, no es necesario conectar manualmente nuestra API, ya que podemos lograrlo directamente a través del App Builder cargándolo como fuente de datos. Primero, debemos asegurarnos de que nuestra API se esté ejecutando, luego navegar a la pestaña Fuentes de datos, seleccionar el icono más y elegir API REST. A partir de ahí, tenemos dos opciones:

  1. Para agregar una definición de Swagger
  2. O usar la URL JSON

Para nuestros propósitos, utilizaremos el enfoque de Swagger y agregaremos la URL.

Tendremos que especificar un nombre para la fuente de datos y continuar con el siguiente paso. A continuación, debemos identificar qué puntos finales queremos incluir. Para esta demostración, seleccionaremos todos los puntos de conexión disponibles. Sin embargo, es importante tener en cuenta que todos los puntos de conexión de los eventos requieren autorización para realizarse correctamente. Por lo tanto, necesitamos obtener un token JWT de un usuario en la API y agregarlo a la pestaña de autorización.

Más adelante en el tutorial, reemplazaremos esto con el token del usuario actual. Una vez establecida la autorización, podemos proceder a Seleccionar datos, asegurarnos de que todos los campos estén seleccionados y hacer clic en Listo.

Select data in App Builder

Una vez que la fuente de datos se ha cargado correctamente, podemos proceder a conectar la cuadrícula en la página del tablero. En primer lugar, seleccione la cuadrícula y actualice la fuente de datos desde el campo Datos. A partir de ahí, podemos agregar operaciones de actualización y eliminación que se vincularán a los puntos finales en nuestra API, lo que permite la modificación en vivo de los datos a través de interacciones con la cuadrícula.

Una vez creadas todas las páginas, podemos previsualizar la aplicación seleccionando el botón verde situado en la esquina superior derecha. A continuación, tenemos que descargar la aplicación para facilitar una mayor personalización.

preview the application by selecting the green button 

Ejecutar la aplicación creada localmente

Una vez descargada la aplicación, descomprime el proyecto y ábrelo en Visual Studio Code. En el terminal, ejecute "npm install" seguido de "npm run start" para comenzar a ejecutar la aplicación.

El siguiente paso es conectar las páginas de inicio de sesión y registro con nuestra API. Para lograr esto, debemos agregar funciones que llamarán a la API. Estas funciones deben añadirse al fichero services/hrdashboard.service.ts donde se almacenan todos nuestros servicios. Debemos añadir dos funciones más, una para el inicio de sesión y otra para el registro.

…
public registerUser(data: any, contentType: string = 'application/json-patch+json, application/json, text/json, application/*+json') {
    const options = {
    headers: {
        'content-type': contentType
    }
};
const body = data;
    return this.http.post(`${API_ENDPOINT}/Auth/Register`, body, options);
}
  public loginUser(data: any, contentType: string = 'application/json-patch+json, application/json, text/json, application/*+json') {
    const options = {
      headers: {
        'content-type': contentType
      }
    };
    const body = data;
    return this.http.post(`${API_ENDPOINT}/Auth/Login`, body, options);
  }
…

En el siguiente paso, navegue hasta el archivo register-page.component.ts y agregue enlaces para las propiedades de entrada. Cree una variable para almacenar mensajes de error y mostrar las validaciones al usuario si la solicitud no se realiza correctamente. Además, agregue una función que se activará cuando se envíe el formulario. Esta función comprobará si todos los campos son obligatorios y, de ser así, almacenará el token JWT en localStorage y navegará hasta la página de inicio. Si falta algún campo, la función debe mostrar un mensaje de error al usuario.

export class RegisterPageComponent {
  email: number;
  firstName: string;
  lastName: string;
  password: string;
  confirmedPassword: string;
  errorMessage: string;
 
  constructor(
    private hRAPIService: HRAPIService,
    private router: Router
  ) { }
  onSubmit(event) {
    event.preventDefault();
    if (this.password !== this.confirmedPassword) {
      this.errorMessage = 'Passwords should match!'
    }
    else if (this.email && this.firstName && this.lastName && this.password) {
      this.hRAPIService.registerUser({ firstName: this.firstName, lastName: this.lastName, email: this.email, password: this.password, confirmedPassword: this.confirmedPassword })
      .subscribe({
        next: (response) => {
          localStorage.setItem('hr_app_token', response['value']);
          this.router.navigateByUrl('/');
        },
        error: (error) => {
          console.log(error)
          this.errorMessage = error.error["errors"] ? Object.values(error.error["errors"])[0] as string : error.error;
        }
      });
    }
    else {
      this.errorMessage = "All fields are required!";
    }
  }
}

También necesitamos actualizar register-page.component.html para vincular las entradas.

<div class="column-layout background"></div>
<div class="column-layout group">
    <h2 class="h2">
            Register
    </h2>
    <p class="error-message">{{errorMessage}}</p>
    <igx-input-group type="border" class="input">
            <input type="text" required igxInput [(ngModel)]="firstName"/>
            <label igxLabel>FirstName</label>
    </igx-input-group>
    <igx-input-group type="border" class="input_1">
            <input type="text" required igxInput [(ngModel)]="lastName"/>
            <label igxLabel>Lastname</label>
    </igx-input-group>
    <igx-input-group type="border" class="input_1">
            <input type="email" required igxInput [(ngModel)]="email"/>
            <label igxLabel>Email</label>
    </igx-input-group>
    <igx-input-group type="border" class="input_1">
            <input type="password" required igxInput [(ngModel)]="password"/>
            <label igxLabel>Password</label>
    </igx-input-group>
    <igx-input-group type="border" class="input_1">
            <input type="password" required igxInput [(ngModel)]="confirmedPassword"/>
            <label igxLabel>Confirm password</label>
    </igx-input-group>
      <button (click)="onSubmit($event)" igxButton="raised" igxRipple class="button">
        Register
      </button>
</div>

Para dar estilo al errorMessage, necesitamos agregar los estilos en register-page.component.scss.

.error-message {
  text-align: center;
  margin: 2rem 0;
  font-weight: bold;
  color: red;
}

Al igual que la página de registro, necesitamos crear propiedades para vincular las entradas y una función que se ejecuta cuando se envía el formulario para la página de inicio de sesión. Esta función llamará al servicio de inicio de sesión para autenticar al usuario enviando su correo electrónico y contraseña. Si la autenticación se realiza correctamente, almacenará el token jwt en localStorage y navegará a la página de inicio. Si se produce un error, mostrará un mensaje de error al usuario. También necesitamos actualizar el login-page.component.html para vincular las entradas.

login.page.component.ts

export class LoginComponent {
  email: number;
  firstName: string;
  lastName: string;
  password: string;
  confirmedPassword: string;
  errorMessage: string;
 
  constructor(
    private hRAPIService: HRAPIService,
    private router: Router
  ) { }
  onSubmit(event) {
    event.preventDefault();
    if (this.email && this.password) {
      this.hRAPIService.loginUser({ email: this.email, password: this.password })
        .subscribe({
          next: (response) => {
            localStorage.setItem('hr_app_token', response['value']);
            this.router.navigateByUrl('/');
          },
          error: (error) => {
            console.log(error)
            this.errorMessage = error.error["errors"] ? Object.values(error.error["errors"])[0] as string : error.error;
          }
        });
    }
    else {
      this.errorMessage = "All fields are required!";
    }
  }
}

login-page.component.html

<div class="column-layout background"></div>
<div class="column-layout group">
    <h2 class="h2">
            Login
    </h2>
    <p class="error-message">{{errorMessage}}</p>
    <igx-input-group type="border" class="input">
            <input type="text" igxInput [(ngModel)]="email"/>
            <label igxLabel>Email</label>
    </igx-input-group>
    <igx-input-group type="border" class="input_1">
            <input type="password" igxInput [(ngModel)]="password"/>
            <label igxLabel>Password</label>
    </igx-input-group>
      <button (click)="onSubmit($event)" igxButton="raised" igxRipple class="button">
        Login
      </button>
</div>

Necesitamos crear un AuthService que nos ayude a decodificar el token, comprobar si el usuario tiene cierto rol y eliminar la sesión. Para ello, crearemos un nuevo archivo llamado auth.service.ts, que deberemos importar al app.module.ts. Para decodificar los tokens, necesitamos instalar el paquete jwt-decode.

import { Injectable } from "@angular/core";
import jwt_decode from 'jwt-decode
';
type Token = {
    Id?: string,
    email?: string,
    firstName?: string,
    exp?: number,
    role?: string,
    sub?: string,
}
@Injectable({
    providedIn: 'root'
  })
  export class AuthService {
    decodeToken(token) {
        return jwt_decode(token);
    }
    getEmail() {
        const token = localStorage.getItem('hr_app_token');
        const {email}: Token = this.decodeToken(token);
        return email;
    }
    isAuthenticated() {
        const token = localStorage.getItem('hr_app_token');
        if (token) {
            const {email, role}: Token = this.decodeToken(token);
            return email != null && role != null;
        }
        return false;
    }
    isAdmin() {
        const token = localStorage.getItem('hr_app_token');
        const {role}: Token = this.decodeToken(token);
        return this.isAuthenticated() && role === "Administrator";
    }
    logout() {
        localStorage.removeItem('hr_app_token');
    }
}

Implementación de guardias para endpoints para una mejor seguridad

Para mejorar la seguridad, necesitamos implementar protecciones para nuestros endpoints. Crearemos tres guardias, empezando por el anonymous-guard.ts. Esta protección garantiza que las páginas de inicio de sesión y registro solo sean accesibles para los usuarios que no han iniciado sesión. Si un usuario que ya ha iniciado sesión intenta acceder a estas páginas, debe ser redirigido a la página de inicio.

Para implementar esta protección, crearemos una carpeta de guardias dentro del directorio de la aplicación y crearemos un nuevo archivo llamado anonymous-guard.ts.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
 
@Injectable({
    providedIn: 'root'
})
export class AnonymousGuard implements CanActivate {
    constructor(private router: Router,
        private authService: AuthService) { }
    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable
<boolean | UrlTree>
| Promise
<boolean | UrlTree>
| boolean | UrlTree {
        if (!this.authService.isAuthenticated()) {
            return true;
        }
        return this.router.parseUrl("/");
    }
}

La siguiente protección que necesitamos implementar se llama auth-guard. Esta protección garantizará que ciertas páginas solo sean accesibles para usuarios autenticados.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
@Injectable({
    providedIn: 'root'
})
export class AuthGuard implements CanActivate {
    constructor(private router: Router,
        private authService: AuthService) { }
    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable
<boolean | UrlTree>
| Promise
<boolean | UrlTree>
| boolean | UrlTree {
        if (this.authService.isAuthenticated()) {
            return true;
        }
        return this.router.parseUrl("/login-page");
    }
}

La tercera guardia, denominada admin-guard, restringirá el acceso a determinadas páginas solo a los usuarios con el rol de administrador.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
 
@Injectable({
    providedIn: 'root'
  })
export class AdminGuard implements CanActivate {
    constructor(private router: Router,
        private authService: AuthService) { }
 
    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable
<boolean | UrlTree>
| Promise
<boolean | UrlTree>
| boolean | UrlTree {
        if (this.authService.isAdmin()) {
            return true;
        }
        return this.router.parseUrl("/login-page");
    }
}

Una vez que hemos creado nuestras guardias, debemos aplicarlas a las rutas adecuadas. Para ello, abra app-routing.module.ts y agregue una propiedad canActivate a cada ruta junto con la protección correspondiente.

Por ejemplo, las páginas de inicio de sesión y registro solo deben ser accesibles para los usuarios que aún no han iniciado sesión, por lo que agregamos AnonymousGuard a sus rutas. La página maestra solo debe ser accesible para los usuarios autenticados, por lo que agregamos AuthGuard a esa ruta. Por último, las páginas add-event y add-role solo deben ser accesibles para los usuarios con rol de administrador, por lo que adjuntamos AdminGuard a esas rutas.

export const routes: Routes = [
  { path: '', redirectTo: 'master-page', pathMatch: 'full' },
  { path: 'error', component: UncaughtErrorComponent },
  { path: 'master-page', loadChildren: () => import('./master-page/master-page.module').then(m => m.MasterPageModule), canActivate: [AuthGuard]},
  { path: 'register-page', component: RegisterPageComponent, data: { text: 'Register Page' }, canActivate: [AnonymousGuard]},
  { path: 'login-page', component: LoginPageComponent, data: { text: 'Login' }, canActivate: [AnonymousGuard]},
  { path: 'add-event', component: AddEventComponent, data: { text: 'Add Event' }, canActivate: [AdminGuard]},
  { path: 'add-role-to-user', component: AddRoleToUserComponent, data: { text: 'Add Role' }, canActivate: [AdminGuard]},
  { path: '**', component: PageNotFoundComponent } // must always be last
];

Para asegurarnos de que los usuarios sin permisos no puedan acceder a determinados enlaces de la navegación, debemos ocultarlos. Para hacer esto, podemos agregar la directiva *ngIf="isUserAdmin()"" a los elementos igx-list-item que corresponden a las opciones ADD EVENT y ADD ROLE TO USER en el archivo master-page.component.html. Al hacerlo, nos aseguramos de que estos enlaces solo sean visibles para los usuarios que tienen privilegios de administrador.

Para implementar esta funcionalidad, también necesitaremos actualizar el archivo master-page.component.ts. Podemos crear una función para verificar si el usuario actual es un administrador y usarla en la directiva *ngIf que agregamos anteriormente.

Además, necesitamos crear una función de cierre de sesión y adjuntarla al evento de clic del igx-list-item que corresponde al enlace LOGOUT. Esto permitirá a los usuarios cerrar sesión en el sistema cuando sea necesario.

Debería verse así:

…
<igx-list-item [isHeader]="false" routerLink="/master-page/add-role-to-user" *ngIf="isUserAdmin()">
<span igxListThumbnail>
    <igx-avatar icon="people" [roundShape]="true" class="avatar_1"></igx-avatar>
</span>
<span igxListLine>
    <p class="ig-typography__subtitle-2 text_3">
              ADD ROLE TO USER
    </p>
</span>
</igx-list-item>
<igx-list-item [isHeader]="false" routerLink="/master-page/add-event" *ngIf="isUserAdmin()">
<span igxListThumbnail>
    <igx-avatar icon="stars" [roundShape]="true" class="avatar_1"></igx-avatar>
</span>
<span igxListLine>
    <p class="ig-typography__subtitle-2 text_3">
              ADD EVENT
    </p>
</span>
</igx-list-item>
<igx-list-item [isHeader]="false" (click)="logout()">
<span igxListThumbnail>
    <igx-avatar icon="exit_to_app" [roundShape]="true" class="avatar_1"></igx-avatar>
</span>
<span igxListLine>
    <p class="ig-typography__subtitle-2 text_3">
              LOGOUT
    </p>
</span>
</igx-list-item>
…
export class MasterPageComponent {
  public listItemVisible = false;
 
  constructor(private authService: AuthService,
    private router: Router){}
  isUserAdmin() {
    return this.authService.isAdmin();
  }
  logout() {
    this.authService.logout();
    this.router.navigateByUrl('/login-page');
  }
}

Nuestro siguiente paso es establecer una conexión entre la página de agregar evento y la API. Para lograr esto, necesitamos crear una nueva función dentro del servicio HRDashboard que manejará la solicitud HTTP POST para crear un nuevo evento.

public postEvent(data: any, contentType: string = 'application/json-patch+json, application/json, text/json, application/*+json'): Observable<any>{
    const options = {
      headers: {
        'content-type': contentType,
        Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,
      },
    };
    const body = data;
    return this.http.post(`${API_ENDPOINT}/Event`, body, options);
  }

Además, en el archivo add-event.component.ts, necesitamos definir propiedades que vincularán los campos de entrada al componente y agregar la función onSubmit. Dado que los correos electrónicos se recibirán en un solo campo separados por comas, tendremos que dividirlos antes de enviarlos a la API.

export class AddEventComponent {
  emails: string;
  category: string;
  title: string;
  date: string;
  errorMessage: string;
 
  constructor(private hrApiService: HRDashboardService,
    private router: Router) {}
  onSubmit(event) {
    event.preventDefault();
    const splitEmails = this.emails.split(', ');
    if (this.emails && this.category && this.title && this.date) {
      this.hrApiService.postEvent({ category: this.category, title: this.title, date: this.date, userEmails: splitEmails})
        .subscribe({
          next: (response) => {
              this.router.navigateByUrl('/');
          },
          error: (error) => {
            console.log(error)
            this.errorMessage = error.error["errors"] ? Object.values(error.error["errors"])[0] as string : error.error;
          }
        });
    }
    else {
      this.errorMessage = "All fields are required!";
    }
  }
}

Actualización del panel de control

Una vez completados los pasos anteriores, podemos pasar a actualizar el tablero. Antes de esto, debemos modificar HRDashboardService para reemplazar todas las apariciones de 'Bearer <auth-token>'con Bearer ${localStorage.getItem('hr_app_token')} en las solicitudes que tienen un encabezado de autorización. Esto garantiza que obtengamos datos utilizando el token JWT correcto.

Además, necesitamos agregar una nueva función a HRDashboardService que obtenga solo los eventos relacionados con el usuario actual.

public getMyEvents(): Observable<any>{
    const options = {
      headers: {
        Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,
      },
    };
    return this.http.get(`${API_ENDPOINT}/Event`, options);
  }

Visualización de eventos del usuario en la página del panel

A continuación, mostraremos los eventos del usuario en la página del panel de control utilizando componentes de tarjeta. Para lograr esto, necesitaremos abrir el archivo dashboard.component.html y usar la directiva *ngFor para renderizar los componentes de igx-card basados en la propiedad myEvents, que contendrá los eventos para el usuario actual. Además, podemos usar *ngIf="isUserAdmin()" para asegurarnos de que la cuadrícula solo sea visible para los administradores. Además, debemos actualizar el saludo en el panel de control para mostrar el correo electrónico del usuario actual, como"¡Buenos días, {{email}}!".

El archivo resultante debe tener el siguiente aspecto:

<div class="row-layout group">
    <div class="column-layout group_1">
        <div class="column-layout group_2">
            <div class="row-layout group_3">
                <div class="column-layout group_4">
                    <h5 class="h5">
                          Good Morning, {{email}}!
                    </h5>
                    <p class="text">
                           Your Highlights
                    </p>
                </div>
            </div>
            <div class="row-layout group_5">
                <igx-card *ngFor="let event of myEvents; index as i;"type="outlined" class="card">
                    <igx-card-media height="200px">
                                    <img src="/assets/Illustration1.svg" class="image" />
                    </igx-card-media>
                    <igx-card-header>
                        <h3 igxCardHeaderTitle>
                                 {{event.title}}
                        </h3>
                        <h5 igxCardHeaderSubtitle>
                                 {{event.category}}
                        </h5>
                        <h5 igxCardHeaderSubtitle>
                                 {{event.date}}
                        </h5>
                    </igx-card-header>
                </igx-card>
            </div>
        </div>
        <div class="row-layout group_6" *ngIf="isUserAdmin()">
            <div class="column-layout group_7">
                <h6 class="h6">
                      All Events
                </h6>
                        <igx-grid [data]="hRDashboardEventAll" primaryKey="id" displayDensity="cosy" [rowEditable]="true" [allowFiltering]="true" filterMode="excelStyleFilter" (rowEditDone)="eventRowEditDone($event)" (rowDeleted)="eventRowDeleted($event)" class="grid">
                          <igx-column field="id" dataType="string" header="id" [sortable]="true" [selectable]="false"></igx-column>
                          <igx-column field="title" dataType="string" header="title" [sortable]="true" [selectable]="false"></igx-column>
                          <igx-column field="category" dataType="string" header="category" [sortable]="true" [selectable]="false"></igx-column>
                          <igx-column field="date" dataType="date" header="date" [sortable]="true" [selectable]="false"></igx-column>
                <igx-action-strip>
                    <igx-grid-pinning-actions></igx-grid-pinning-actions>
                    <igx-grid-editing-actions [addRow]="true"></igx-grid-editing-actions>
                </igx-action-strip>
                        </igx-grid>
            </div>
        </div>
    </div>
</div>

En el archivo dashboard.component.ts, necesitaremos definir dos propiedades: myEvents y email. Estas propiedades deben rellenarse con los datos relevantes de la función ngOnInit.

export class DashboardComponent implements OnInit {
  public hRDashboardEventAll: any = null;
  myEvents: any;
  email: any;
  constructor(
    private hRDashboardService: HRDashboardService,
    private authService: AuthService,
  ) {}
  ngOnInit() {
    this.hRDashboardService.getEventAll().subscribe(data => this.hRDashboardEventAll = data);
    this.hRDashboardService.getMyEvents().subscribe(data => this.myEvents = data);
    this.email = this.authService.getEmail();
  }
  public isUserAdmin() {
    return this.authService.isAdmin();
  }
…

Ahora podemos ver en el panel de control todos los eventos para el usuario actual y desde la cuadrícula, si el usuario es administrador, puede actualizar y eliminar las entradas desde allí.

Conexión de la función Add Role a la página de usuario y a la API

El último paso es establecer una conexión entre la función de adición a la página de usuario y la API. Para lograr esto, necesitaremos crear una función dentro del servicio HRDashboard que obtenga los datos del usuario de la API y complete el componente de selección de correos electrónicos.

public getUsers(): Observable
<any>
{
    const options = {
      headers: {
        Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,
      },
    };
    return this.http.get(`${API_ENDPOINT}/User`, options);
  }
 
  public changeUserRole(data: any): Observable
<any>
{
    const options = {
      headers: {
        Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,
      },
    };
    const body = data;
    return this.http.post(`${API_ENDPOINT}/User/Role`, body, options);
  }

Una vez que hayamos terminado con eso, podemos ir a add-role-to-user.component.ts y buscarlos. También debemos crear la función onSubmit que va a llamar a changeUserRole desde el servicio HRDashboard. El resultado final debería verse así:

export class AddRoleToUserComponent {
  users: any;
  email: string;
  role: string;
  constructor(private hrApiService: HRDashboardService,
    private router: Router) { }
  ngOnInit() {
    this.hrApiService.getUsers()
      .subscribe(data => {
        this.users = data;
      });
  }
 
  onSubmit(event) {
    event.preventDefault();
    if (this.email && this.role) {
      this.hrApiService.changeUserRole({ email: this.email, role: this.role})
        .subscribe({
          next: (response) => {
              this.router.navigateByUrl('/');
          },
          error: (error) => {
            console.log(error)
          }
        });
    }
  }
}
<div class="row-layout group">
    <div class="column-layout group_1">
        <h2 class="h2">
                  Add Role to user
        </h2>
        <div class="row-layout group_2">
                  <igx-select type="border" class="select"[(ngModel)]="email">
            <igx-select-item *ngFor="let user of users; index as i;" value="{{user.email}}">
                          {{user.email}}
            </igx-select-item>
                    <label igxLabel>Email</label>
                  </igx-select>
                  <igx-select type="border" class="select"[(ngModel)]="role">
            <igx-select-item value="Administrator">
                          Administrator
            </igx-select-item>
                    <label igxLabel>Role</label>
                  </igx-select>
        </div>
            <button igxButton="raised" (click)="onSubmit($event)" igxRipple class="button">
              Submit
            </button>
    </div>
</div>

Después de seguir los pasos necesarios y completar las tareas requeridas, ahora tenemos una aplicación completamente funcional que ha sido construida con App Builder e integrada con una API. Esto significa que nuestra aplicación ahora es capaz de comunicarse con la API, lo que permite a los usuarios realizar diversas acciones, como crear nuevos eventos, agregar roles a los usuarios y ver su panel de control personalizado.  Puedes ver el código completo de la demo en GitHub.

¿Cómo crear una aplicación en App Builder utilizando una API basada en roles?
Reserve una demostración