Skip to content

Commit 3b4e261

Browse files
Use store for list page and ad import aliases
1 parent 24ff709 commit 3b4e261

21 files changed

+9264
-6732
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.angular
22
node_modules
3+
dist

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"@angular/router": "^17.2.0",
2323
"@angular/ssr": "^17.2.2",
2424
"@ngrx/store": "^17.1.1",
25-
"@ngrx/store-devtools": "^17.1.1",
25+
"@ngrx/store-devtools": "^17.2.0",
2626
"express": "^4.18.2",
2727
"rxjs": "~7.8.0",
2828
"tslib": "^2.3.0",
@@ -46,4 +46,4 @@
4646
"tailwindcss": "^3.4.1",
4747
"typescript": "~5.3.2"
4848
}
49-
}
49+
}

src/app/app.config.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@ import {provideClientHydration} from '@angular/platform-browser';
66
import {provideStore} from '@ngrx/store';
77
import {provideStoreDevtools} from '@ngrx/store-devtools';
88
import {provideHttpClient, withFetch} from "@angular/common/http";
9+
import {listReducer} from "./store/reducer/list.reducer";
910

1011
export const appConfig: ApplicationConfig = {
1112
providers: [
1213
provideRouter(routes),
1314
provideHttpClient(withFetch()),
1415
provideClientHydration(),
15-
provideStore(
16-
reducer
17-
),
18-
provideStoreDevtools()
16+
provideStore(reducer),
17+
provideStoreDevtools({
18+
maxAge: 25, autoPause: true, // Pauses recording actions and state changes when the extension window is not open
19+
trace: false, // If set to true, will include stack trace for every dispatched action, so you can see it in trace tab jumping directly to that part of code
20+
traceLimit: 75, // maximum stack trace frames to be stored (in case trace option was provided as true)
21+
connectInZone: true // If set to true, the connection is established within the Angular zone
22+
})
1923
]
2024
};

src/app/components/common/table/table.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</tr>
1717
</thead>
1818
<tbody>
19-
@for (item of items; track item) {
19+
@for (item of items | async; track item) {
2020
<tr>
2121
<td class="w-2">
2222
<input type="checkbox"

src/app/components/common/table/table.component.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
import {Component, EventEmitter, Input, Output} from '@angular/core';
22
import {RouterLink} from "@angular/router";
3-
import {Hero} from "../../../interface/hero.model";
43
import {FormsModule} from "@angular/forms";
5-
import {ShowComponent} from "../../svg/show/show.component";
64
import {ShowSvgComponent} from "../../svg/show-svg/show-svg.component";
75
import {EditSvgComponent} from "../../svg/edit-svg/edit-svg.component";
6+
import {Observable} from "rxjs";
7+
import {Hero} from "../../../interface/hero.model";
8+
import {AsyncPipe} from "@angular/common";
89

910
@Component({
1011
selector: 'app-table',
1112
standalone: true,
1213
imports: [
1314
RouterLink,
1415
FormsModule,
15-
ShowComponent,
1616
ShowSvgComponent,
17-
EditSvgComponent
17+
EditSvgComponent,
18+
AsyncPipe
1819
],
1920
templateUrl: './table.component.html',
2021
})
2122
export class TableComponent {
22-
@Input() items!: Hero[];
23+
@Input() items!: Observable<Hero[]| undefined>;
2324
@Input() bulk!: Array<string>;
2425
@Output() addToBulkList = new EventEmitter<string>()
2526
@Output() selectedAll = new EventEmitter<Function>()

src/app/components/foo/list/list.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ <h1 class="text-3xl mb-2">Heroes List</h1>
1414
</app-delete>
1515
</div>
1616
</div>
17-
@if (isLoading()) {
17+
@if (isLoading$ | async) {
1818
<div class="bg-blue-100 rounded py-4 px-4 text-blue-700 text-sm">Loading ...</div>
1919
} @else {
20-
<app-table [items]="heroes()"
20+
<app-table [items]="list$"
2121
[bulk]="bulk()"
2222
(addToBulkList)="addToBulk($event)"
2323
(selectedAll)="selectedAll()"

src/app/components/foo/list/list.component.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import {Component, computed, OnInit, Output, signal, WritableSignal} from '@angular/core';
1+
import {Component, OnInit, signal, WritableSignal} from '@angular/core';
22
import {RouterLink} from "@angular/router";
33
import {AsyncPipe, Location, NgFor, NgIf} from "@angular/common";
4-
import {TableComponent} from "../../common/table/table.component";
5-
import {HeroService} from "../../../service/hero.service";
6-
import {Hero} from "../../../interface/hero.model";
7-
import {DeleteComponent} from "../../common/delete/delete.component";
8-
import {log} from "node:util";
9-
import {Validators} from "@angular/forms";
4+
import {Store} from "@ngrx/store";
5+
import {Observable} from "rxjs";
6+
import {DeleteComponent} from "@components/common/delete/delete.component";
7+
import {TableComponent} from "@components/common/table/table.component";
8+
import {Hero} from "@interface/hero.model";
9+
import {List} from "@interface/list.model";
10+
import {HeroService} from "@service/hero.service";
11+
import {isLoadingAction, ListActions} from "@store/action/foo.actions";
12+
import {selectorListError, selectorListItems, selectorListLoading} from "@store/selector/list.selectors";
1013

1114
@Component({
1215
selector: 'app-list',
@@ -22,43 +25,54 @@ import {Validators} from "@angular/forms";
2225
templateUrl: './list.component.html',
2326
})
2427
export class ListComponent implements OnInit {
25-
public heroes: WritableSignal<Hero[] | []> = signal([])
26-
public isLoading = signal(false)
27-
public error = signal(undefined)
28+
public isLoading$: Observable<Boolean | undefined> = this.store.select(selectorListLoading);
29+
public list$: Observable<Hero[] | undefined> = this.store.select(selectorListItems);
30+
public listState$ = this.store.select('list')
31+
public error$: Observable<String | undefined> = this.store.select(selectorListError);
2832
public bulk: WritableSignal<Array<string>> = signal([])
2933

3034
constructor(
35+
private store: Store<{ list: List }>,
3136
private heroService: HeroService,
3237
private location: Location
3338
) {
39+
3440
}
3541

3642
ngOnInit() {
37-
this.isLoading.set(true)
3843
this.heroService
3944
.getHeroes('/heroes')
4045
.subscribe(
4146
(items) => {
42-
this.heroes.set(items['hydra:member'])
43-
this.isLoading.set(false)
47+
this.store.dispatch(isLoadingAction({isLoading: true}))
48+
this.store.dispatch(ListActions({
49+
items: items['hydra:member']
50+
}))
51+
this.store.dispatch(isLoadingAction({isLoading: false}))
4452
}
4553
)
4654
}
4755

4856
addToBulk(id: string) {
4957
if (this.isInBulkList(id)) {
50-
const bulkFilter = this.bulk().filter(element => element !== id)
58+
const bulkFilter =
59+
this.bulk()
60+
.filter(element => element !== id)
5161
return this.bulk.set(bulkFilter)
5262
}
5363

5464
this.bulk.update(uri => [...uri, id])
5565
}
5666

57-
selectedAll() {
67+
async selectedAll() {
5868
if (!this.bulk().length) {
59-
this.heroes().forEach(hero => {
60-
this.bulk().push(<string>hero["@id"])
61-
})
69+
await this.list$
70+
.forEach(item =>
71+
item?.forEach(i =>
72+
this.bulk().push(<string>i["@id"]
73+
)
74+
)
75+
)
6276
} else {
6377
this.bulk.set([])
6478
}

src/app/components/svg/edit-svg/edit-svg.component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Component } from '@angular/core';
55
standalone: true,
66
imports: [],
77
templateUrl: './edit-svg.component.svg',
8-
styleUrl: './edit-svg.component.css'
98
})
109
export class EditSvgComponent {
1110

src/app/components/svg/list-svg/list-svg.component.css

Whitespace-only changes.

src/app/components/svg/list-svg/list-svg.component.spec.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/app/components/svg/list-svg/list-svg.component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Component } from '@angular/core';
55
standalone: true,
66
imports: [],
77
templateUrl: './list-svg.component.svg',
8-
styleUrl: './list-svg.component.css'
98
})
109
export class ListSvgComponent {
1110

src/app/components/svg/show-svg/show-svg.component.svg

Lines changed: 1 addition & 1 deletion
Loading

src/app/components/svg/show-svg/show-svg.component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Component } from '@angular/core';
55
standalone: true,
66
imports: [],
77
templateUrl: './show-svg.component.svg',
8-
styleUrl: './show-svg.component.css'
98
})
109
export class ShowSvgComponent {
1110

src/app/interface/list.model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Hero} from "./hero.model";
22

33
export interface List {
4-
isLoading?: Boolean | undefined | null,
4+
isLoading?: Boolean,
55
items?: Hero[],
66
error?: string,
77
}

src/app/store/action/foo.actions.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import {createAction, props} from "@ngrx/store";
22
import {Hero} from "../../interface/hero.model";
3+
import {List} from "../../interface/list.model";
4+
import {Show} from "../../interface/show.model";
5+
import {Update} from "../../interface/update.model";
36

47
export const ListActions = createAction(
5-
'[FETCH] List', props<{ items?: Array<Hero>, isLoading?: Boolean, error?: string }>()
8+
'[FETCH] List', props<List>()
9+
)
10+
11+
export const isLoadingAction = createAction(
12+
'IS LOADING', props<{ isLoading: boolean }>()
613
)
714

815
export const showActions = createAction(
9-
'[FETCH] Show', props<{ items?: Array<Hero>, isLoading?: Boolean, error?: string }>()
16+
'[FETCH] Show', props<Show>()
1017
)
1118

1219
export const UpdateActions = createAction(
13-
'[API] Update', props<{ item?: Hero, isLoading?: Boolean, error?: string }>()
20+
'[API] Update', props<Update>()
1421
)
1522

1623
export const DeleteActions = createAction(

src/app/store/reducer/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import {heroesReducer} from "./heroes.reducer";
21
import {showReducer} from "./show.reducer";
32
import {updateReducer} from "./update.reducer";
3+
import {listReducer} from "./list.reducer";
44

55
export default {
6-
heroes: heroesReducer,
76
show: showReducer,
8-
delete: updateReducer
7+
delete: updateReducer,
8+
list: listReducer
99
}

src/app/store/reducer/list.reducer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {createReducer, on} from "@ngrx/store";
22
import * as FooAction from '../action/foo.actions'
33
import {List} from "../../interface/list.model";
44

5-
65
export const initialStateList: List = {
76
isLoading: false,
87
items: [],
@@ -16,5 +15,9 @@ export const listReducer = createReducer(
1615
isLoading,
1716
items,
1817
error
18+
})),
19+
on(FooAction.isLoadingAction, (state, {isLoading}) => ({
20+
...state,
21+
isLoading
1922
}))
2023
)

src/app/store/reducer/show.reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {HeroesActions} from "../action/heroes.actions";
44

55
export const initialStateShow: Show = {
66
isLoading: false,
7-
item: undefined,
7+
item: {},
88
error: ''
99
}
1010

tsconfig.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@
2222
"lib": [
2323
"ES2022",
2424
"dom"
25-
]
25+
],
26+
"baseUrl": "./src",
27+
"paths": {
28+
"@components/*" : ["app/components/*"],
29+
"@interface/*" : ["app/interface/*"],
30+
"@service/*" : ["app/service/*"],
31+
"@store/*" : ["app/store/*"],
32+
}
2633
},
2734
"angularCompilerOptions": {
2835
"enableI18nLegacyMessageIdFormat": false,

0 commit comments

Comments
 (0)