콘텐츠로 건너뛰기
역할 기반 API를 사용하여 App Builder에서 앱을 만드는 방법은 무엇입니까?

역할 기반 API를 사용하여 App Builder에서 앱을 만드는 방법은 무엇입니까?

이 단계별 가이드에서는 모든 기능을 갖춘 맞춤형 앱을 제작하는 방법을 보여드리겠습니다. 이 기사의 목적에 따라 로우 코드와 역할 기반 API를 사용하겠습니다.

20분 읽기

이 흥미로운 튜토리얼에서는 이전 튜토리얼에서 구축한 APIApp Builder TM 플랫폼이라는 두 가지 강력한 도구를 결합하여 기술을 한 단계 끌어올릴 것입니다. 이를 통해 다양한 플랫폼에서 사용할 수 있는 완전한 기능과 사용자 정의 가능한 응용 프로그램을 만들 것입니다.

App Builder는 사용자가 최소한의 코딩 경험으로 강력한 애플리케이션을 만들 수 있는 강력한 도구입니다. 사용자 친화적인 인터페이스를 통해 다양한 요소를 쉽게 끌어다 놓아 세련되고 전문적인 응용 프로그램을 즉시 만들고 Angular, Blazor 또는 Web Components에서 코드를 생성할 수 있습니다.

로우 코드 App Builder로 첫 번째 응용 프로그램 만들기

시작하려면 App Builder 실행하고 "새 응용 프로그램 만들기"를 선택하십시오. 그런 다음 "샘플 앱" 섹션으로 이동하여 HR 대시보드를 프로젝트의 기본 디자인으로 선택합니다. 여기에서 특정 요구 사항에 맞게 디자인을 확장하고 사용자 지정할 수 있습니다.

App Builder에서 새 응용 프로그램 만들기

샘플을 열면 여러 페이지가 이미 만들어졌음을 알 수 있습니다. 그러나 프로젝트의 요구 사항에 더 잘 맞도록 이러한 페이지 중 일부를 수정하고 새 페이지도 만들어야 합니다.

App Builder에서 앱 변경

이제 로그인 및 등록 페이지를 만들어 보겠습니다. "보기" 탭으로 이동하고 더하기 아이콘을 선택하여 "페이지 등록"이라는 새 페이지를 만듭니다.

예제 로그인 만들기 및 App Builder에서 페이지 등록

일관성을 유지하기 위해 마스터 페이지의 배경을 등록 페이지에도 다시 사용할 수 있습니다. 열 레이아웃을 추가해야 합니다. 이 레이아웃 내에는 Register 콘텐츠가 있는 제목과 단추와 함께 5개의 입력 필드가 포함됩니다. 모든 입력 필드는 필수여야 하며 적절한 유형이 지정되어야 합니다.

App Builder의 열 레이아웃

다음으로 로그인 화면을 만들 수 있습니다.이 화면에는 두 개의 입력 필드(이메일용과 비밀번호용)만 필요합니다. 프로세스를 단순화하기 위해 등록 페이지를 복제하고 불필요한 요소를 제거할 수 있습니다.

App Builder의 로그인 페이지 예

두 페이지가 모두 생성되면 제출 버튼 아래에 각 페이지에 대한 링크를 추가할 수 있습니다.

App Builder에서 두 페이지 사이에 링크 추가

홈 페이지에는 현재 사용자가 카드 구성 요소에서 참석하고 있는 모든 이벤트를 표시하는 대시보드가 있습니다. 사용자에게 관리자 역할이 있는 경우 플랫폼의 모든 이벤트가 포함된 그리드도 표시되므로 필요에 따라 CRUD 작업을 수행할 수 있습니다.

App Builder의 이벤트 작업

앞으로 새 이벤트를 추가하기 위한 페이지를 만들 것입니다.이 페이지는 관리자 역할이 있는 사용자만 액세스할 수 있지만 자습서의 뒷부분에서 다룹니다. 각 이벤트에 대해 제목, 카테고리, 참석 사용자의 이메일 및 이벤트 날짜가 필요합니다.

App Builder에서 새 이벤트를 추가하기 위한 페이지 만들기

또한 사용자 역할을 변경하기 위해 유사한 페이지를 만들어야 합니다. 이벤트 페이지와 마찬가지로 이 기능은 관리자만 액세스할 수 있습니다. 이 데모에서는 다른 사용자에게 관리자 권한을 부여하는 것만 지원합니다.

App Builder에서 사용자 역할을 변경하기 위한 유사한 페이지 만들기

모든 페이지가 생성되면 사이드바 탐색에 연결할 수 있습니다.

App Builder의 사이드바 탐색에 연결

API를 수동으로 연결할 필요가 없습니다.

다행히도 API를 데이터 소스로 업로드하여 App Builder를 통해 직접 연결할 수 있으므로 수동으로 연결할 필요가 없습니다. 먼저 API가 실행 중인지 확인한 다음 데이터 소스 탭으로 이동하여 더하기 아이콘을 선택하고 REST API를 선택해야 합니다. 거기에서 두 가지 옵션이 있습니다.

  1. Swagger 정의를 추가하려면
  2. 또는 JSON URL을 사용하려면

우리의 목적을 위해 Swagger 접근 방식을 활용하고 URL을 추가합니다.

데이터 소스의 이름을 지정하고 다음 단계로 진행해야 합니다. 그런 다음 포함할 엔드포인트를 식별해야 합니다. 이 데모에서는 사용 가능한 모든 엔드포인트를 선택합니다. 그러나 이벤트에 대한 모든 엔드포인트가 성공하려면 권한 부여가 필요하다는 점에 유의해야 합니다. 따라서 API의 사용자로부터 JWT 토큰을 가져와 권한 부여 탭에 추가해야 합니다.

자습서의 뒷부분에서 이 토큰을 현재 사용자의 토큰으로 바꿉니다. 권한 부여가 설정되면 데이터 선택으로 이동하여 모든 필드가 선택되었는지 확인하고 완료를 클릭할 수 있습니다.

App Builder에서 데이터 선택

데이터 원본이 성공적으로 업로드되면 대시보드 페이지에서 그리드 연결을 진행할 수 있습니다. 먼저 그리드를 선택하고 데이터 필드에서 데이터 원본을 업데이트합니다. 여기에서 API의 엔드포인트에 연결될 업데이트 및 삭제 작업을 추가하여 그리드와의 상호 작용을 통해 데이터를 실시간으로 수정할 수 있습니다.

모든 페이지가 생성되면 오른쪽 상단 모서리에 있는 녹색 버튼을 선택하여 응용 프로그램을 미리 볼 수 있습니다. 그런 다음 추가 사용자 지정을 용이하게 하기 위해 응용 프로그램을 다운로드해야 합니다.

녹색 버튼을 선택하여 응용 프로그램을 미리 봅니다.

생성된 앱을 로컬에서 실행

애플리케이션이 다운로드되면 프로젝트의 압축을 풀고 Visual Studio Code에서 엽니다. 터미널에서 "npm install"을 실행한 다음 "npm run start"를 실행하여 애플리케이션 실행을 시작합니다.

다음 단계는 로그인 및 등록 페이지를 API에 연결하는 것입니다. 이를 위해서는 API를 호출할 함수를 추가해야 합니다. 이러한 기능은 모든 서비스가 저장되는 services/hrdashboard.service.ts 파일에 추가되어야 합니다. 로그인용과 등록용의 두 가지 기능을 더 추가해야 합니다.

…
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);
  }
…

다음 단계에서는 register-page.component.ts 파일로 이동하여 입력 속성에 대한 바인딩을 추가합니다. 오류 메시지를 저장하고 요청이 실패한 경우 사용자에게 유효성 검사를 표시하는 변수를 만듭니다. 또한 양식이 제출될 때 트리거되는 함수를 추가합니다. 이 함수는 모든 필드가 필요한지 확인하고, 필요한 경우 JWT 토큰을 localStorage에 저장하고 홈페이지로 이동합니다. 누락된 필드가 있는 경우 함수는 사용자에게 오류 메시지를 표시해야 합니다.

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!";
    }
  }
}

또한 입력을 바인딩하기 위해 register-page.component.html 업데이트해야 합니다.

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

errorMessage의 스타일을 지정하려면 register-page.component.scss에 스타일을 추가해야 합니다.

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

등록 페이지와 마찬가지로 입력을 바인딩하는 속성과 로그인 페이지에 대해 양식이 제출될 때 실행되는 함수를 만들어야 합니다. 이 함수는 로그인 서비스를 호출하여 이메일과 암호를 전송하여 사용자를 인증합니다. 인증에 성공하면 jwt 토큰을 localStorage에 저장하고 홈 페이지로 이동합니다. 실패하면 사용자에게 오류 메시지가 표시됩니다. 또한 입력을 바인딩하기 위해 login-page.component.html 업데이트해야 합니다.

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>

토큰을 디코딩하고, 사용자에게 특정 역할이 있는지 확인하고, 세션을 제거하는 데 도움이 되는 AuthService를 만들어야 합니다. 이를 위해 auth.service.ts 라는 새 파일을 만들어 app.module.ts로 가져와야 합니다. 토큰을 디코딩하려면 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');
    }
}

보안 강화를 위한 엔드포인트에 대한 가드 구현

보안을 강화하려면 엔드포인트에 대한 가드를 구현해야 합니다. anonymous-guard.ts부터 시작하여 세 명의 경비원을 만들 것입니다. 이 가드는 로그인하지 않은 사용자만 로그인 및 등록 페이지에 액세스할 수 있도록 합니다. 이미 로그인한 사용자가 이러한 페이지에 액세스하려고 하면 홈 페이지로 리디렉션되어야 합니다.

이 가드를 구현하기 위해 app 디렉토리 내에 guards 폴더를 만들고 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("/");
    }
}

다음으로 구현해야 할 가드는 auth-guard 입니다. 이 가드는 인증된 사용자만 특정 페이지에 액세스할 수 있도록 합니다.

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");
    }
}

admin-guard라는 세 번째 가드는 특정 페이지에 대한 액세스를 관리자 역할이 있는 사용자로만 제한합니다.

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");
    }
}

가드를 만든 후에는 적절한 경로에 적용해야 합니다. 이렇게 하려면 app-routing.module.ts 열고 해당 가드와 함께 각 경로에 canActivate 속성을 추가합니다.

예를 들어 로그인 및 등록 페이지는 아직 로그인하지 않은 사용자만 액세스할 수 있어야 하므로 해당 경로에 AnonymousGuard를 추가합니다. 마스터 페이지는 인증된 사용자만 액세스할 수 있어야 하므로 해당 경로에 AuthGuard를 추가합니다. 마지막으로, add-event 및 add-role 페이지는 관리자 역할이 있는 사용자만 액세스할 수 있어야 하므로 해당 경로에 AdminGuard를 연결합니다.

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
];

권한이 없는 사용자가 탐색의 특정 링크에 액세스할 수 없도록 하려면 해당 링크를 숨겨야 합니다. 이를 위해 master-page.component.html 파일의 ADD EVENT 및 ADD ROLE TO USER 옵션에 해당하는 igx-list-item 요소에 *ngIf="isUserAdmin()" 지시문을 추가할 수 있습니다. 이렇게 하면 이러한 링크가 관리자 권한이 있는 사용자만 볼 수 있습니다.

이 기능을 구현하려면 master-page.component.ts 파일도 업데이트해야 합니다. 현재 사용자가 관리자인지 확인하는 함수를 만들고 이전에 추가한 *ngIf 지시문에서 사용할 수 있습니다.

또한 로그아웃 함수를 생성하여 LOGOUT 링크에 해당하는 igx-list-item의 클릭 이벤트에 첨부해야 합니다. 이렇게 하면 사용자가 필요할 때 시스템에서 로그아웃할 수 있습니다.

다음과 같이 표시되어야 합니다.

…
<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');
  }
}

다음 단계는 이벤트 추가 페이지와 API 간의 연결을 설정하는 것입니다. 이를 위해서는 HRDashboard 서비스 내에서 새 이벤트를 만들기 위한 HTTP POST 요청을 처리할 새 함수를 만들어야 합니다.

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);
  }

또한 add-event.component.ts 파일에서 입력 필드를 구성 요소에 바인딩하고 onSubmit 함수를 추가하는 속성을 정의해야 합니다. 이메일은 쉼표로 구분된 단일 필드로 수신되므로 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!";
    }
  }
}

대시보드 업데이트

위의 단계가 완료되면 대시보드 업데이트로 넘어갈 수 있습니다. 이에 앞서 권한 부여 헤더가 있는 요청에서 'Bearer <auth-token>'의 모든 항목을 Bearer ${localStorage.getItem('hr_app_token')}로 바꾸도록 HRDashboardService를 수정해야 합니다. 이렇게 하면 올바른 JWT 토큰을 사용하여 데이터를 가져올 수 있습니다.

또한 현재 사용자와 관련된 이벤트만 가져오는 HRDashboardService에 새 함수를 추가해야 합니다.

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

대시보드 페이지에 사용자 이벤트 표시

다음으로, 카드 구성 요소를 사용하여 대시보드 페이지에 사용자의 이벤트를 표시합니다. 이를 위해서는 dashboard.component.html 파일을 열고 *ngFor 지시문을 사용하여 현재 사용자에 대한 이벤트를 포함할 myEvents 속성을 기반으로 igx 카드 구성 요소를 렌더링해야 합니다. 또한 *ngIf="isUserAdmin()"을 사용하여 그리드가 관리자만 볼 수 있도록 할 수 있습니다. 또한 대시보드의 인사말을 업데이트하여 "Good Morning, {{email}}!"과 같이 현재 사용자의 이메일을 표시해야 합니다.

결과 파일은 다음과 같아야 합니다.

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

dashboard.component.ts 파일에서 myEventsemail의 두 가지 속성을 정의해야 합니다. 이러한 속성은 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();
  }
…

이제 대시보드에서 현재 사용자에 대한 모든 이벤트를 볼 수 있으며, 사용자가 관리자인 경우 그리드에서 항목을 업데이트하고 삭제할 수 있습니다.

사용자 페이지에 역할 추가 및 API 연결

마지막 단계는 사용자 페이지에 역할 추가와 API 간의 연결을 설정하는 것입니다. 이를 위해서는 HRDashboard 서비스 내에서 API에서 사용자 데이터를 가져오고 이메일 선택 구성 요소를 채우는 함수를 만들어야 합니다.

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);
  }

이 작업이 끝나면 add-role-to-user.component.ts에 가서 가져올 수 있습니다. 또한 HRDashboard 서비스에서 changeUserRole을 호출할 onSubmit 함수도 만들어야 합니다. 최종 결과는 다음과 같아야 합니다.

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>

필요한 단계를 따르고 필요한 작업을 완료하면 이제 App Builder로 구축되고 API와 통합된 완전한 기능을 갖춘 애플리케이션이 있습니다. 즉, 이제 애플리케이션이 API와 통신할 수 있으므로 사용자가 새 이벤트 생성, 사용자에게 역할 추가, 개인화된 대시보드 보기와 같은 다양한 작업을 수행할 수 있습니다. GitHub에서 데모의 전체 코드를 볼 수 있습니다.

데모 요청