Skip to content

Commit 8a53bc2

Browse files
author
Armen Vardanyan
committed
Backup
1 parent cdecd51 commit 8a53bc2

12 files changed

+150
-8
lines changed

database.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
{
1212
"id": 1,
1313
"name": "Car repair"
14+
},
15+
{
16+
"id": 3
1417
}
1518
],
1619
"expenses": [
@@ -27,4 +30,4 @@
2730
"amount": 300
2831
}
2932
]
30-
}
33+
}

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@angular/platform-browser": "~9.0.0",
2222
"@angular/platform-browser-dynamic": "~9.0.0",
2323
"@angular/router": "~9.0.0",
24+
"@ngrx/effects": "^12.2.0",
2425
"@ngrx/store": "^9.1.2",
2526
"rxjs": "~6.5.4",
2627
"tslib": "^1.10.0",

src/app/app.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { BrowserModule } from '@angular/platform-browser';
22
import { NgModule } from '@angular/core';
3+
import { FormsModule } from '@angular/forms';
34
import { StoreModule } from '@ngrx/store';
45
import { MatListModule } from '@angular/material/list';
6+
import { MatInputModule } from '@angular/material/input';
7+
import { MatButtonModule } from '@angular/material/button';
58

69
import { AppRoutingModule } from './app-routing.module';
710
import { AppComponent } from './app.component';
@@ -22,6 +25,9 @@ import { CategoryListPresenterComponent } from './category-list/category-list-pr
2225
BrowserAnimationsModule,
2326
StoreModule.forRoot({categories: categoryReducer}),
2427
MatListModule,
28+
MatInputModule,
29+
MatButtonModule,
30+
FormsModule,
2531
],
2632
providers: [],
2733
bootstrap: [AppComponent]

src/app/category-list/category-list-container/category-list-container.component.html

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

src/app/category-list/category-list-container/category-list-container.component.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import { Component, OnInit } from '@angular/core';
22
import { Store } from '@ngrx/store';
33

4+
import { addCategory, categoriesListLoaded, deleteCategory } from 'src/app/state/actions';
5+
import { Category } from 'src/app/state/models';
46
import { categories } from 'src/app/state/selectors';
57

68
@Component({
79
selector: 'app-category-list-container',
8-
template: `<app-category-list-presenter [categories]="categories$ | async"></app-category-list-presenter>`,
10+
template: `
11+
<app-category-list-presenter [categories]="categories$ | async"
12+
(categoryAdded)="addCategory($event)"
13+
(categoryDeleted)="deleteCategory($event)">
14+
</app-category-list-presenter>`,
915
styleUrls: ['./category-list-container.component.scss']
1016
})
1117
export class CategoryListContainerComponent implements OnInit {
@@ -16,6 +22,15 @@ export class CategoryListContainerComponent implements OnInit {
1622
) { }
1723

1824
ngOnInit() {
25+
this.store.dispatch(categoriesListLoaded());
26+
}
27+
28+
addCategory(category: Category) {
29+
this.store.dispatch(addCategory({payload: category})); // this is where magic happens
30+
}
31+
32+
deleteCategory(categoryName: string) {
33+
this.store.dispatch(deleteCategory({payload: categoryName}));
1934
}
2035

2136
}
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
<mat-list>
2-
<mat-list-item *ngFor="let category of categories">{{ category.name }}</mat-list-item>
2+
<mat-list-item *ngFor="let category of categories">
3+
{{ category.name }}
4+
<button mat-button (click)="deleteCategory(category.name)">Delete</button>
5+
</mat-list-item>
36
</mat-list>
7+
<mat-form-field>
8+
<mat-label>New Category Name:</mat-label>
9+
<input matInput [(ngModel)]="newCategoryName"/>
10+
<button mat-button (click)="addCategory()">Add Category</button>
11+
</mat-form-field>

src/app/category-list/category-list-presenter/category-list-presenter.component.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Input } from '@angular/core';
1+
import { Component, Input, Output, EventEmitter } from '@angular/core';
22
import { Category } from 'src/app/state/models';
33

44
@Component({
@@ -8,4 +8,15 @@ import { Category } from 'src/app/state/models';
88
})
99
export class CategoryListPresenterComponent {
1010
@Input() categories: Category[] = [];
11+
@Output() categoryAdded = new EventEmitter<Category>();
12+
@Output() categoryDeleted = new EventEmitter<string>();
13+
newCategoryName = '';
14+
15+
addCategory() {
16+
this.categoryAdded.emit({name: this.newCategoryName});
17+
}
18+
19+
deleteCategory(categoryName: string) {
20+
this.categoryDeleted.emit(categoryName);
21+
}
1122
}

src/app/services/category.service.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Injectable } from '@angular/core';
2+
import { HttpClient } from '@angular/common/http';
3+
import { Category } from '../state/models';
4+
5+
@Injectable({providedIn: 'root'})
6+
export class CategoryService {
7+
8+
readonly baseUrl = 'http://localhost:3000/categories';
9+
10+
constructor(
11+
private readonly http: HttpClient,
12+
) {}
13+
14+
getCategories() {
15+
return this.http.get<Category[]>(this.baseUrl);
16+
}
17+
18+
getCategoryById(id: number) {
19+
return this.http.get<Category>(`${this.baseUrl}/${id}`);
20+
}
21+
22+
addCategory(category: Category) {
23+
return this.http.post<Category>(this.baseUrl, category);
24+
}
25+
26+
deleteCategory(id: number) {
27+
return this.http.delete<void>(`${this.baseUrl}/${id}`);
28+
}
29+
}

src/app/state/actions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
11
import { createAction, props } from '@ngrx/store';
2+
import { Category } from './models';
23

34
export const addCategory = createAction('[Category List] Add Category', props<{payload: {name: string}}>());
5+
export const deleteCategory = createAction('[Category List] Delete Category', props<{payload: number}>());
6+
7+
export const addCategorySuccess = createAction('[Category List] Add Category Success', props<{payload: Category}>());
8+
9+
export const addCategoryError = createAction('[Category List] Add Category Error');
10+
11+
export const categoriesListLoaded = createAction('[Category List] Categories List Loaded');
12+
export const loadCategoriesSuccess = createAction('[Category List] Load Categories Success', props<{payload: Category[]}>());
13+
export const loadCategoriesError = createAction('[Category List] Load Categories Error');
14+
15+
export const deleteCategorySuccess = createAction('[Category List] Delete Category Success', props<{payload: number}>());
16+
export const deleteCategoryError = createAction('[Category List] Delete Category Error');

src/app/state/effects.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Actions, createEffect, ofType } from '@ngrx/effects';
2+
import { of } from 'rxjs';
3+
import { mergeMap, map, catchError } from 'rxjs/operators';
4+
5+
import { CategoryService } from '../services/category.service';
6+
import { categoriesListLoaded, loadCategoriesSuccess, loadCategoriesError, deleteCategory, deleteCategorySuccess, addCategory, addCategorySuccess, addCategoryError } from './actions';
7+
8+
export class CategoriesEffects {
9+
10+
categoriesListLoaded$ = createEffect(() => this.actions$.pipe(
11+
ofType(categoriesListLoaded),
12+
mergeMap(() => this.categoriesService.getCategories().pipe(
13+
map(categories => loadCategoriesSuccess({payload: categories})),
14+
catchError(() => of(loadCategoriesError())),
15+
))
16+
));
17+
18+
deleteCategory$ = createEffect(() => this.actions$.pipe(
19+
ofType(deleteCategory),
20+
mergeMap(({payload}) => this.categoriesService.deleteCategory(payload).pipe(
21+
map(() => deleteCategorySuccess({payload})),
22+
catchError(() => of(loadCategoriesError())),
23+
))
24+
));
25+
26+
addCategory$ = createEffect(() => this.actions$.pipe(
27+
ofType(addCategory),
28+
mergeMap(({payload}) => this.categoriesService.addCategory(payload).pipe(
29+
map((result) => addCategorySuccess({payload: result})),
30+
catchError(() => of(addCategoryError())),
31+
)),
32+
));
33+
34+
constructor(
35+
private readonly actions$: Actions,
36+
private readonly categoriesService: CategoryService,
37+
) { }
38+
39+
}

src/app/state/reducer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { Action, createReducer, on } from '@ngrx/store';
2-
import { addCategory } from './actions';
2+
import { addCategory, loadCategoriesSuccess } from './actions';
33

44
import { CategoryState, initialState } from './state';
55

66
const _reducer = createReducer(
77
initialState,
88
on(addCategory, (state, action) => ({...state, categories: [...state.list, action.payload]})),
9+
on(loadCategoriesSuccess, (state, action) => ({...state, categories: action.payload})),
910
);
11+
1012
export function categoryReducer(state: CategoryState, action: Action) {
1113
return _reducer(state, action);
1214
}

0 commit comments

Comments
 (0)