Skip to content

Commit d6002bf

Browse files
error handling
1 parent 3469ad5 commit d6002bf

File tree

13 files changed

+190
-115
lines changed

13 files changed

+190
-115
lines changed

src/generators/AngularGenerator.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export default class extends BaseGenerator {
3636
"app/components/common/svg/menu/menu.component.ts",
3737
"app/components/common/back-to-list/back-to-list.component.html",
3838
"app/components/common/back-to-list/back-to-list.component.ts",
39+
"app/components/common/alert/alert.component.html",
40+
"app/components/common/alert/alert.component.ts",
3941

4042
// COMPONENTS
4143
"app/components/foo/create/create.component.html",
@@ -67,6 +69,9 @@ export default class extends BaseGenerator {
6769

6870
handlebars.registerHelper("compare", hbhComparison.compare);
6971
handlebars.registerHelper("lowercase", hbhString.lowercase);
72+
handlebars.registerHelper("get_length", function (obj) {
73+
return obj.length;
74+
});
7075
}
7176

7277
help(resource) {
@@ -124,6 +129,7 @@ export default class extends BaseGenerator {
124129
`${dir}/app/components/${lc}/list`,
125130
`${dir}/app/components/${lc}/show`,
126131
`${dir}/app/components/${lc}/table`,
132+
`${dir}/app/components/common/alert`,
127133
`${dir}/app/components/common/back-to-list`,
128134
`${dir}/app/components/common/delete`,
129135
`${dir}/app/components/common/header`,
@@ -158,6 +164,8 @@ export default class extends BaseGenerator {
158164
"app/components/common/sidebar/sidebar.component.ts",
159165
"app/components/common/back-to-list/back-to-list.component.html",
160166
"app/components/common/back-to-list/back-to-list.component.ts",
167+
"app/components/common/alert/alert.component.html",
168+
"app/components/common/alert/alert.component.ts",
161169
"app/interface/api.ts",
162170
"app/service/api.service.ts",
163171
"app/app.component.html",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="rounded py-4 px-4 text-sm mt-2"
2+
[class]="type === 'loading' ? 'bg-blue-100 text-blue-700' : 'bg-red-100 text-red-700'">
3+
@if (type === 'loading') {
4+
Loading ...
5+
}
6+
@if (type === 'error') {
7+
<h3 class="text-lg">\{{ error()?.['name'] }} <span class="text-sm">\{{ error()?.['status'] }}</span></h3>
8+
<p>\{{ error()?.['message'] }}</p>
9+
}
10+
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {Component, Input, WritableSignal} from '@angular/core';
2+
import {SubmissionErrors} from "@interface/api";
3+
4+
@Component({
5+
selector: 'app-alert',
6+
standalone: true,
7+
imports: [],
8+
templateUrl: './alert.component.html'
9+
})
10+
export class AlertComponent {
11+
@Input() type!: 'loading' | 'error';
12+
@Input() error!: WritableSignal<SubmissionErrors | null>;
13+
}

templates/angular/app/components/foo/create/create.component.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
<app-back-to-list url="/{{lc}}s" />
44
</div>
55
@if (isLoading()) {
6-
<div class="bg-blue-100 rounded py-4 px-4 text-blue-700 text-sm">Loading ...</div>
7-
} @else {
8-
<h1 class="text-3xl my-4">Create</h1>
9-
<app-form-{{lc}} [item]="item()" (submit)="onSubmit($event)"/>
6+
<app-alert type="loading"/>
7+
}
8+
@if (error()) {
9+
<app-alert type="error" [error]="error"/>
1010
}
11+
<h1 class="text-3xl my-4">Create {{title}}</h1>
12+
<app-form-{{lc}} [item]="item()" (submit)="onSubmit($event)"/>
1113
</div>

templates/angular/app/components/foo/create/create.component.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@ import {Location} from "@angular/common";
22
import {Component, inject, signal, WritableSignal} from '@angular/core';
33
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
44
import {RouterLink} from "@angular/router";
5+
import {AlertComponent} from "@components/common/alert/alert.component"
56
import {BackToListComponent} from "@components/common/back-to-list/back-to-list.component";
67
import {DeleteComponent} from "@components/common/delete/delete.component";
78
import {FormComponent} from "@components/{{lc}}/form/form.component";
8-
import {ApiItem} from "@interface/api";
9+
import {ApiItem, SubmissionErrors} from "@interface/api";
910
import {ApiService} from "@service/api.service";
1011

1112
@Component({
1213
selector: 'app-create-{{lc}}',
1314
standalone: true,
1415
imports: [
16+
AlertComponent,
1517
BackToListComponent,
1618
DeleteComponent,
1719
RouterLink,
@@ -26,16 +28,17 @@ export class CreateComponent {
2628
private location: Location = inject(Location)
2729
public item: WritableSignal<ApiItem> = signal({} as ApiItem)
2830
public isLoading: WritableSignal<boolean> = signal(false)
31+
public error: WritableSignal<SubmissionErrors | null> = signal(null)
2932

3033
onSubmit(data: any) {
3134
return this.apiService
32-
.add('/{{lc}}',
33-
this.item()
34-
).subscribe(
35-
(item) => {
35+
.add("/books", this.item())
36+
.subscribe({
37+
next: () => {
3638
this.isLoading.set(true)
3739
this.location.back()
38-
}
39-
)
40+
},
41+
error: (err: SubmissionErrors) => this.error.set(err)
42+
})
4043
}
4144
}
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
<div class="px-4 mt-4">
22
<div class="flex items-center justify-end">
3-
<app-back-to-list url="/{{lc}}s" />
3+
<app-back-to-list url="/{{lc}}s"/>
44
</div>
55
@if (isLoading()) {
6-
<div class="bg-blue-100 rounded py-4 px-4 text-blue-700 text-sm">Loading ...</div>
7-
} @else if (error()) {
8-
<div class="bg-red-100 rounded py-4 px-4 text-blue-700 text-sm">Error ...</div>
9-
} @else {
10-
<h1 class="text-3xl my-4">Edit \{{ item()['name'] }} <span class="text-xl">\{{ item()["@id"] }} </span></h1>
11-
<app-form-{{lc}} [item]="item()"
12-
(submit)="onSubmit($event)"
13-
(delete)="delete()"
14-
/>
6+
<app-alert type="loading"/>
7+
}
8+
@if (error()) {
9+
<app-alert type="error" [error]="error"/>
1510
}
11+
<h1 class="text-3xl my-4">
12+
Edit \{{ item()['name'] }}
13+
<span class="text-xl">\{{ item()["@id"] }}</span>
14+
</h1>
15+
<app-form-{{lc}}
16+
[item]="item()"
17+
(submit)="onSubmit($event)"
18+
(delete)="delete()"
19+
/>
1620
</div>
Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
import {CommonModule, Location} from "@angular/common";
1+
import {CommonModule, Location} from "@angular/common"
22
import {
33
Component,
44
DestroyRef,
55
inject,
66
OnInit,
77
signal,
88
WritableSignal
9-
} from '@angular/core';
10-
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
11-
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
12-
import {Router, RouterLink} from "@angular/router";
13-
import {BackToListComponent} from "@components/common/back-to-list/back-to-list.component";
14-
import {DeleteComponent} from "@components/common/delete/delete.component";
15-
import {FormComponent} from "@components/{{lc}}/form/form.component";
16-
import {ApiItem} from "@interface/api";
17-
import {ApiService} from "@service/api.service";
9+
} from '@angular/core'
10+
import {takeUntilDestroyed} from "@angular/core/rxjs-interop"
11+
import {FormsModule, ReactiveFormsModule} from "@angular/forms"
12+
import {Router, RouterLink} from "@angular/router"
13+
import {AlertComponent} from "@components/common/alert/alert.component"
14+
import {BackToListComponent} from "@components/common/back-to-list/back-to-list.component"
15+
import {DeleteComponent} from "@components/common/delete/delete.component"
16+
import {FormComponent} from "@components/{{lc}}/form/form.component"
17+
import {ApiItem, SubmissionErrors} from "@interface/api"
18+
import {ApiService} from "@service/api.service"
1819

1920
@Component({
2021
selector: 'app-edit-{{lc}}',
2122
standalone: true,
2223
imports: [
24+
AlertComponent,
2325
BackToListComponent,
2426
CommonModule,
2527
DeleteComponent,
@@ -33,34 +35,50 @@ import {ApiService} from "@service/api.service";
3335
export class EditComponent implements OnInit {
3436
public item: WritableSignal<ApiItem> = signal({} as ApiItem);
3537
public isLoading: WritableSignal<Boolean> = signal(false)
36-
public error: WritableSignal<string> = signal('')
37-
38+
public error: WritableSignal<SubmissionErrors | null> = signal(null)
3839
private destroy: DestroyRef = inject(DestroyRef)
3940
private apiService: ApiService = inject(ApiService)
4041
private router: Router = inject(Router)
4142
private location: Location = inject(Location)
4243

43-
4444
ngOnInit() {
45-
const uri = this.router.url.split('/edit')[0]
46-
this.isLoading.set(true)
47-
this.apiService.fetchData(uri)
45+
this.fetchData()
46+
}
47+
48+
public fetchData() {
49+
const uri = this.router.url.split("/edit")[0]
50+
this.toggleIsLoading()
51+
this.apiService
52+
.fetchData(uri)
4853
.pipe(takeUntilDestroyed(this.destroy))
49-
.subscribe(value => {
50-
this.item.set(value)
51-
this.isLoading.set(false)
54+
.subscribe({
55+
next: (value) => {
56+
this.item.set(value)
57+
},
58+
error: err => this.error.set(err)
5259
})
60+
this.toggleIsLoading()
5361
}
5462

55-
onSubmit(data: any) {
63+
public onSubmit(data: any) {
5664
return this.apiService
5765
.put(this.item()["@id"]!, this.item())
58-
.subscribe(() => this.location.back());
66+
.subscribe({
67+
next: () => this.location.back(),
68+
error: err => this.error.set(err)
69+
})
5970
}
6071

61-
delete() {
72+
public delete() {
6273
return this.apiService
63-
.delete(this.item()['@id']!)
64-
.subscribe(() => this.location.back())
74+
.delete(this.item()["@id"]!)
75+
.subscribe({
76+
next: () => this.location.back(),
77+
error: err => this.error.set(err)
78+
})
79+
}
80+
81+
private toggleIsLoading() {
82+
return this.isLoading.update((value) => !value);
6583
}
6684
}

templates/angular/app/components/foo/list/list.component.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@ <h1 class="text-3xl mb-2">{{title}} List</h1>
1414
</div>
1515
</div>
1616
@if (isLoading()) {
17-
<div class="bg-blue-100 rounded py-4 px-4 text-blue-700 text-sm">Loading ...</div>
18-
} @else {
17+
<app-alert type="loading"/>
18+
}
19+
@if (error()) {
20+
<app-alert type="error" [error]="error"/>
21+
}
1922
<app-table-{{lc}} [items]="items"
2023
[bulk]="bulk()"
2124
(addToBulkList)="addToBulk($event)"
2225
(selectedAll)="selectedAll()"
2326
/>
2427
@if (pagination()) {
2528
<app-pagination
26-
[pagination]="pagination!"
29+
[pagination]="pagination"
2730
(handleChangePage)="changePage($event)"
2831
/>
2932
}
30-
}
3133
</div>

templates/angular/app/components/foo/list/list.component.ts

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import {
2-
AsyncPipe,
3-
Location,
42
NgFor,
53
NgIf
64
} from "@angular/common";
@@ -12,11 +10,12 @@ import {
1210
signal,
1311
WritableSignal
1412
} from '@angular/core';
15-
import {Router, RouterLink} from "@angular/router";
13+
import {RouterLink} from "@angular/router";
1614
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
15+
import {AlertComponent} from "@components/common/alert/alert.component";
1716
import {DeleteComponent} from "@components/common/delete/delete.component";
1817
import {TableComponent} from "@components/{{lc}}/table/table.component";
19-
import {ApiItem, Pagination} from "@interface/api";
18+
import {ApiItem, Pagination, SubmissionErrors} from "@interface/api";
2019
import {ApiService} from "@service/api.service";
2120
import {PaginationComponent} from "@components/common/pagination/pagination.component";
2221

@@ -29,15 +28,16 @@ import {PaginationComponent} from "@components/common/pagination/pagination.comp
2928
TableComponent,
3029
NgIf,
3130
DeleteComponent,
32-
PaginationComponent
31+
PaginationComponent,
32+
AlertComponent
3333
],
3434
templateUrl: './list.component.html',
3535
})
3636
export class ListComponent implements OnInit {
3737
public isLoading: WritableSignal<Boolean> = signal(false)
38-
public pagination: WritableSignal<Pagination> = signal({} as Pagination)
38+
public pagination: WritableSignal<Pagination | undefined> = signal(undefined)
3939
public items: WritableSignal<ApiItem[]> = signal([])
40-
public error: WritableSignal<String> = signal('')
40+
public error: WritableSignal<SubmissionErrors | null> = signal(null)
4141
public bulk: WritableSignal<Array<string>> = signal([])
4242
public uri: WritableSignal<string> = signal('/{{lc}}s')
4343
private apiService: ApiService = inject(ApiService)
@@ -48,43 +48,48 @@ export class ListComponent implements OnInit {
4848
}
4949

5050
public fetchData() {
51-
this.toggleIsLoading()
51+
this.toggleIsLoading();
5252
this.apiService
5353
.fetchDataList(this.uri())
54+
// Unsubscribe event for more performance
5455
.pipe(takeUntilDestroyed(this.destroy))
55-
.subscribe((items) => {
56-
this.toggleIsLoading();
57-
if (items['hydra:view']) this.pagination.set(items['hydra:view'])
58-
this.items.set(items["hydra:member"])
56+
.subscribe({
57+
next: items => {
58+
if (items["hydra:view"]) this.pagination.set(items["hydra:view"]);
59+
this.items.set(items["hydra:member"]);
60+
},
61+
error: (err: SubmissionErrors) => this.error.set(err)
5962
})
63+
this.toggleIsLoading();
6064
}
6165

6266
public addToBulk(id: string) {
6367
if (this.isInBulkList(id)) {
64-
const bulkFilter =
65-
this.bulk()
66-
.filter(element => element !== id)
67-
return this.bulk.set(bulkFilter)
68+
const bulkFilter = this.bulk().filter((element) => element !== id);
69+
return this.bulk.set(bulkFilter);
6870
}
69-
70-
this.bulk.update(uri => [...uri, id])
71+
this.bulk.update((uri) => [...uri, id]);
7172
}
7273

7374
public selectedAll() {
7475
if (!this.bulk().length) {
75-
this.items().forEach(item => {
76-
this.bulk().push(<string>item["@id"])
77-
})
76+
this.items().forEach((item) => {
77+
this.bulk().push(<string>item["@id"]);
78+
});
7879
} else {
79-
this.bulk.set([])
80+
this.bulk.set([]);
8081
}
8182
}
8283

8384
public delete() {
84-
Promise.all(this.bulk()).then(items =>
85-
items.forEach(uri =>
86-
this.apiService.delete(uri).subscribe(() => {
87-
window.location.reload()
85+
Promise.all(this.bulk()).then((items) =>
86+
items.forEach((uri) =>
87+
this.apiService
88+
.delete(uri).subscribe({
89+
next: () => {
90+
window.location.reload();
91+
},
92+
error: (err: SubmissionErrors) => this.error.set(err)
8893
})
8994
)
9095
)

0 commit comments

Comments
 (0)