Создание компонента для ошибки 500 (внутренняя ошибка сервера)
В папке error-pages мы собираемся создать новый компонент, набрав команду AngularCLI
:
ng g component error-pages/internal-server --skipTests
Давайте изменим internal-server.component.ts
:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-internal-server',
templateUrl: './internal-server.component.html',
styleUrls: ['./internal-server.component.css']
})
export class InternalServerComponent implements OnInit {
public errorMessage: string = "500 SERVER ERROR, CONTACT ADMINISTRATOR!!!!";
constructor() { }
ngOnInit() {
}
}
Затем изменим internal-server.component.html
:
<p>
{{errorMessage}}
</p>
Кроме того, мы собираемся модифицировать internal-server.component.css
:
p{
font-weight: bold;
font-size: 50px;
text-align: center;
color: #c72d2d;
}
Наконец, давайте изменим app.module.ts
:
RouterModule.forRoot([
{ path: 'home', component: HomeComponent },
{ path: 'owner', loadChildren: () => import('./owner/owner.module').then(m => m.OwnerModule) },
{ path: '404', component: NotFoundComponent},
{ path: '500', component: InternalServerComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', redirectTo: '/404', pathMatch: 'full'}
])
Мы создали наш компонент, и пора создать сервис для обработки ошибок.
Создание службы для обработки ошибок в Angular
В папке shared/services создайте новую службу и назовите ее error-handler.service.ts:
ng g service shared/services/error-handler --skipTests
Давайте изменим этот файл error-handler.service.ts
:
import { Injectable } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class ErrorHandlerService {
public errorMessage: string = '';
constructor(private router: Router) { }
public handleError = (error: HttpErrorResponse) => {
if(error.status === 500){
this.handle500Error(error);
}
else if(error.status === 404){
this.handle404Error(error)
}
else{
this.handleOtherError(error);
}
}
private handle500Error = (error: HttpErrorResponse) => {
this.createErrorMessage(error);
this.router.navigate(['/500']);
}
private handle404Error = (error: HttpErrorResponse) => {
this.createErrorMessage(error);
this.router.navigate(['/404']);
}
private handleOtherError = (error: HttpErrorResponse) => {
this.createErrorMessage(error);
//TODO: this will be fixed later;
}
private createErrorMessage = (error: HttpErrorResponse) => {
this.errorMessage = error.error ? error.error : error.statusText;
}
}
Прежде всего, мы вводим Router
, который мы используем для перенаправления пользователя на другие страницы в коде. В методе handleError()
мы проверяем код состояния ошибки и на основе этого вызываем правильный частный метод для обработки этой ошибки. Функции handle404Error()
и handle500Error()
отвечают за заполнение свойства errorMessage
. Мы собираемся использовать это свойство как модальное сообщение об ошибке или сообщение об ошибке на странице. Позже мы поговорим о функции handleOtherError()
, поэтому с комментарием внутри.
Если вы помните в файле owner-list.component.ts
, мы извлекаем всех владельцев с сервера. Но в этом файле нет обработки ошибок. Итак, давайте продолжим изменение этого файла owner-list.component.ts
для реализации функции обработки ошибок Angular:
import { Component, OnInit } from '@angular/core';
import { RepositoryService } from './../../shared/services/repository.service';
import { Owner } from './../../_interfaces/owner.model';
import { ErrorHandlerService } from './../../shared/services/error-handler.service';
@Component({
selector: 'app-owner-list',
templateUrl: './owner-list.component.html',
styleUrls: ['./owner-list.component.css']
})
export class OwnerListComponent implements OnInit {
public owners: Owner[];
public errorMessage: string = '';
constructor(private repository: RepositoryService, private errorHandler: ErrorHandlerService) { }
ngOnInit() {
this.getAllOwners();
}
public getAllOwners = () => {
let apiAddress: string = "api/owner";
this.repository.getData(apiAddress)
.subscribe(res => {
this.owners = res as Owner[];
},
(error) => {
this.errorHandler.handleError(error);
this.errorMessage = this.errorHandler.errorMessage;
})
}
}
Вы можете проверить это, изменив код в методе сервера GetAllOwners
. В качестве первой строки кода добавьте return NotFound()
или return StatusCode(500, “Some message”)
, и вы наверняка будете перенаправлены на правильную страницу с ошибкой.
Подготовка компонента "Информация о владельце"
Давайте продолжим, создав компонент сведений о владельце:
ng g component owner/owner-details --skipTests
Нам понадобится, чтобы изменить файл owner.module.ts
:
RouterModule.forChild([
{ path: 'list', component: OwnerListComponent },
{ path: 'details/:id', component: OwnerDetailsComponent }
])
Как видите, у нового пути есть идентификатор параметра. Итак, когда мы нажимаем кнопку Details, мы собираемся передать этот идентификатор нашему маршруту, и мы собираемся получить владельца с этим точным идентификатором в компоненте OwnerDetails.
Нам нужно добавить новый интерфейс в папку _interfaces
:
export interface Account{
id: string;
dateCreated: Date;
accountType: string;
ownerId?: string;
}
И измените интерфейс Owner
:
import { Account } from './account.model';
export interface Owner{
id: string;
name: string;
dateOfBirth: Date;
address: string;
accounts?: Account[];
}
Используя вопросительный знак, мы делаем поле необязательным.
Чтобы продолжить, изменим owner-list.component.html
:
<button type="button" id="details" class="btn btn-light"
(click)="getOwnerDetails(owner.id)">Details</button>
При событии щелчка мы вызываем функцию getOwnerDetails
и передаем идентификатор владельца в качестве параметра. Итак, нам нужно обработать это событие щелчка в нашем файле owner-list.component.ts
.
Добавьте оператор импорта:
import { Router } from '@angular/router';
Затем измените конструктор и добавьте функцию getOwnerDetails(id)
:
constructor(private repository: RepositoryService, private errorHandler: ErrorHandlerService,
private router: Router) { }
public getOwnerDetails = (id) => {
const detailsUrl: string = `/owner/details/${id}`;
this.router.navigate([detailsUrl]);
}
Реализация компонента "Информация о владельце"
У нас есть весь код для поддержки компонента сведений о владельце. Пришло время реализовать бизнес-логику внутри этого компонента.
Сначала измените файл owner-details.component.ts
:
import { Component, OnInit } from '@angular/core';
import { Owner } from './../../_interfaces/owner.model';
import { Router, ActivatedRoute } from '@angular/router';
import { RepositoryService } from './../../shared/services/repository.service';
import { ErrorHandlerService } from './../../shared/services/error-handler.service';
@Component({
selector: 'app-owner-details',
templateUrl: './owner-details.component.html',
styleUrls: ['./owner-details.component.css']
})
export class OwnerDetailsComponent implements OnInit {
public owner: Owner;
public errorMessage: string = '';
constructor(private repository: RepositoryService, private router: Router,
private activeRoute: ActivatedRoute, private errorHandler: ErrorHandlerService) { }
ngOnInit() {
this.getOwnerDetails()
}
getOwnerDetails = () => {
let id: string = this.activeRoute.snapshot.params['id'];
let apiUrl: string = `api/owner/${id}/account`;
this.repository.getData(apiUrl)
.subscribe(res => {
this.owner = res as Owner;
},
(error) =>{
this.errorHandler.handleError(error);
this.errorMessage = this.errorHandler.errorMessage;
})
}
}
Это в значительной степени та же логика, что и в файле owner-list.component.ts
, за исключением того, что теперь у нас есть импортированный ActivatedRoute
, потому что нам нужно получить наш идентификатор из маршрута.
После выполнения функции getOwnerDetails
мы собираемся сохранить объект-владелец со всеми связанными учетными записями внутри свойства owner
.
Все, что нам нужно сделать, это изменить файл owner-details.component.html
:
<div class="card card-body bg-light mb-2 mt-2">
<div class="row">
<div class="col-md-3">
<strong>Owner name:</strong>
</div>
<div class="col-md-3">
{{owner?.name}}
</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>Date of birth:</strong>
</div>
<div class="col-md-3">
{{owner?.dateOfBirth | date: 'dd/MM/yyyy'}}
</div>
</div>
<div class="row" *ngIf='owner?.accounts.length <= 2; else advancedUser'>
<div class="col-md-3">
<strong>Type of user:</strong>
</div>
<div class="col-md-3">
<span class="text-success">Beginner user.</span>
</div>
</div>
<ng-template #advancedUser>
<div class="row">
<div class="col-md-3">
<strong>Type of user:</strong>
</div>
<div class="col-md-3">
<span class="text-info">Advanced user.</span>
</div>
</div>
</ng-template>
</div>
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Account type</th>
<th>Date created</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let account of owner?.accounts">
<td>{{account?.accountType}}</td>
<td>{{account?.dateCreated | date: 'dd/MM/yyyy'}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
В этом примере кода мы условно отображаем сущность владельца. Более того, мы отображаем все аккаунты, связанные с этим владельцем:
Заключение
Прочитав этот пост, вы узнали:
- Как обрабатывать ошибки в отдельной службе с помощью обработки ошибок Angular
- Способ использования условного рендеринга HTML-страницы.
- Как создать страницу сведений о вашей организации
Спасибо, что прочитали этот пост, надеюсь, он был вам полезен.
В следующей части статье я покажу вам, как создавать дочерние компоненты и как использовать @Input
, @Output
и EventEmmiters
в Angular. Поступая таким образом, вы научитесь разбивать компоненты на более мелкие части (родительские и дочерние компоненты).