Browse Source

24-314 Moving data logic to NgRx, removing shopping list service

ngrx
Nils Dittberner 8 years ago
parent
commit
569a9da503
8 changed files with 122 additions and 64 deletions
  1. +0
    -2
      src/app/core/core.module.ts
  2. +6
    -2
      src/app/recipes/recipe-detail/recipe-detail.component.ts
  3. +3
    -11
      src/app/recipes/recipe.service.ts
  4. +34
    -1
      src/app/shopping-list/ngrx/shopping-list.actions.ts
  5. +58
    -2
      src/app/shopping-list/ngrx/shopping-list.reducers.ts
  6. +17
    -15
      src/app/shopping-list/shopping-edit/shopping-edit.component.ts
  7. +4
    -4
      src/app/shopping-list/shopping-list.component.ts
  8. +0
    -27
      src/app/shopping-list/shopping-list.service.ts

+ 0
- 2
src/app/core/core.module.ts View File

@@ -5,7 +5,6 @@ import { HeaderComponent } from "./header/header.component";
import { HomeComponent } from "./home/home.component"; import { HomeComponent } from "./home/home.component";
import { SharedModule } from "../shared/shared.module"; import { SharedModule } from "../shared/shared.module";
import { AppRoutingModule } from "../app-routing.module"; import { AppRoutingModule } from "../app-routing.module";
import { ShoppingListService } from "../shopping-list/shopping-list.service";
import { RecipeService } from "../recipes/recipe.service"; import { RecipeService } from "../recipes/recipe.service";
import { DataStorageService } from "../shared/data-storage.service"; import { DataStorageService } from "../shared/data-storage.service";
import { AuthService } from "../auth/auth.service"; import { AuthService } from "../auth/auth.service";
@@ -26,7 +25,6 @@ import { LoggingInterceptor } from "../shared/logging.interceptor";
HeaderComponent HeaderComponent
], ],
providers: [ providers: [
ShoppingListService,
RecipeService, RecipeService,
DataStorageService, DataStorageService,
AuthService, AuthService,


+ 6
- 2
src/app/recipes/recipe-detail/recipe-detail.component.ts View File

@@ -1,8 +1,11 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router'; import { Router, ActivatedRoute, Params } from '@angular/router';
import { Store } from '@ngrx/store';


import { Recipe } from '../recipe.model'; import { Recipe } from '../recipe.model';
import { RecipeService } from '../recipe.service'; import { RecipeService } from '../recipe.service';
import * as ShoppingListActions from '../../shopping-list/ngrx/shopping-list.actions';
import * as fromShoppingList from '../../shopping-list/ngrx/shopping-list.reducers';


@Component({ @Component({
selector: 'app-recipe-detail', selector: 'app-recipe-detail',
@@ -15,7 +18,8 @@ export class RecipeDetailComponent implements OnInit {
constructor(private recipeService: RecipeService, constructor(private recipeService: RecipeService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router) { }
private router: Router,
private store: Store<fromShoppingList.AppState>) { }


ngOnInit() { ngOnInit() {
this.route.params.subscribe( this.route.params.subscribe(
@@ -27,7 +31,7 @@ export class RecipeDetailComponent implements OnInit {
} }


onAddToShoppingList() { onAddToShoppingList() {
this.recipeService.addIngredientsToShoppingList(this.recipe.ingredients);
this.store.dispatch(new ShoppingListActions.AddIngredients(this.recipe.ingredients));
} }


onEditRecipe() { onEditRecipe() {


+ 3
- 11
src/app/recipes/recipe.service.ts View File

@@ -1,17 +1,13 @@
import { EventEmitter } from "@angular/core";
import { Subject } from "rxjs/Subject";

import { Recipe } from "./recipe.model"; import { Recipe } from "./recipe.model";
import { EventEmitter, Injectable } from "@angular/core";
import { Ingredient } from "../shared/ingredient.model"; import { Ingredient } from "../shared/ingredient.model";
import { ShoppingListService } from "../shopping-list/shopping-list.service";
import { Subject } from "rxjs/Subject";
import { nextTick } from "q";


@Injectable()
export class RecipeService { export class RecipeService {
recipesChanged = new Subject<Recipe[]>(); recipesChanged = new Subject<Recipe[]>();
private recipes: Recipe[] = []; private recipes: Recipe[] = [];


constructor(private shoppingListService: ShoppingListService) { }

replaceRecipes(recipes: Recipe[]) { replaceRecipes(recipes: Recipe[]) {
this.recipes = recipes; this.recipes = recipes;
this.recipesChanged.next(this.recipes.slice()); this.recipesChanged.next(this.recipes.slice());
@@ -25,10 +21,6 @@ export class RecipeService {
return this.recipes[index]; return this.recipes[index];
} }


addIngredientsToShoppingList(ingredients: Ingredient[]) {
this.shoppingListService.addIngredients(ingredients);
}

addRecipe(recipe: Recipe) { addRecipe(recipe: Recipe) {
this.recipes.push(recipe); this.recipes.push(recipe);
this.recipesChanged.next(this.recipes.slice()); this.recipesChanged.next(this.recipes.slice());


+ 34
- 1
src/app/shopping-list/ngrx/shopping-list.actions.ts View File

@@ -3,6 +3,11 @@ import { Action } from '@ngrx/store';
import { Ingredient } from '../../shared/ingredient.model'; import { Ingredient } from '../../shared/ingredient.model';


export const ADD_INGREDIENT = 'ADD_INGREDIENT'; export const ADD_INGREDIENT = 'ADD_INGREDIENT';
export const ADD_INGREDIENTS = 'ADD_INGREDIENTS';
export const UPDATE_INGREDIENT = 'UPDATE_INGREDIENT';
export const DELETE_INGREDIENT = 'DELETE_INGREDIENT';
export const START_EDIT = 'START_EDIT';
export const STOP_EDIT = 'STOP_EDIT';


export class AddIngredient implements Action { export class AddIngredient implements Action {
readonly type = ADD_INGREDIENT; readonly type = ADD_INGREDIENT;
@@ -10,4 +15,32 @@ export class AddIngredient implements Action {
constructor(public payload: Ingredient) {} constructor(public payload: Ingredient) {}
} }


export type ShoppingListActions = AddIngredient;
export class AddIngredients implements Action {
readonly type = ADD_INGREDIENTS;
constructor(public payload: Ingredient[]) {}
}

export class UpdateIngredient implements Action {
readonly type = UPDATE_INGREDIENT;
constructor(public payload: Ingredient) {}
}

export class DeleteIngredient implements Action {
readonly type = DELETE_INGREDIENT;
}

export class StartEdit implements Action {
readonly type = START_EDIT;
constructor(public payload: number) {}
}

export class StopEdit implements Action {
readonly type = STOP_EDIT;
}



export type ShoppingListActions = AddIngredient | AddIngredients | UpdateIngredient | DeleteIngredient | StartEdit | StopEdit;

+ 58
- 2
src/app/shopping-list/ngrx/shopping-list.reducers.ts View File

@@ -2,12 +2,27 @@ import * as ShoppingListActions from './shopping-list.actions';


import { Ingredient } from '../../shared/ingredient.model'; import { Ingredient } from '../../shared/ingredient.model';


export interface AppState {
shoppingList: State
}

export interface State {
ingredients: Ingredient[];
editedIngredient: Ingredient;
editedIngredientIndex: number;
}

export const ADD_INGREDIENT = 'ADD_INGREDIENT'; export const ADD_INGREDIENT = 'ADD_INGREDIENT';
export const ADD_INGREDIENTS = 'ADD_INGREDIENTS';
export const UPDATE_INGREDIENT = 'UPDATE_INGREDIENT';
export const DELETE_INGREDIENT = 'DELETE_INGREDIENT';


const initialState = {
const initialState: State = {
ingredients: [ ingredients: [
new Ingredient('Banana', 10) new Ingredient('Banana', 10)
]
],
editedIngredient: null,
editedIngredientIndex: -1
}; };


export function shoppingListReducer(state = initialState, action: ShoppingListActions.ShoppingListActions) { export function shoppingListReducer(state = initialState, action: ShoppingListActions.ShoppingListActions) {
@@ -17,6 +32,47 @@ export function shoppingListReducer(state = initialState, action: ShoppingListAc
...state, ...state,
ingredients: [...state.ingredients, action.payload] ingredients: [...state.ingredients, action.payload]
}; };
case ShoppingListActions.ADD_INGREDIENTS:
return {
...state,
ingredients: [...state.ingredients, ...action.payload]
};
case ShoppingListActions.UPDATE_INGREDIENT:
const ingredient = state.ingredients[state.editedIngredientIndex];
const updatedIngredient = {
...ingredient,
...action.payload
}
const ingredients = [...state.ingredients];
ingredients[state.editedIngredientIndex] = updatedIngredient;
return {
...state,
ingredients: ingredients,
editedIngredient: null,
editedIngredientIndex: -1
};
case ShoppingListActions.DELETE_INGREDIENT:
const oldIngredients = [...state.ingredients];
oldIngredients.splice(state.editedIngredientIndex, 1);
return {
...state,
ingredients: oldIngredients,
editedIngredient: null,
editedIngredientIndex: -1
};
case ShoppingListActions.START_EDIT:
const editedIngredient = {...state.ingredients[action.payload]};
return {
...state,
editedIngredient: editedIngredient,
editedIngredientIndex: action.payload
}
case ShoppingListActions.STOP_EDIT:
return {
...state,
editedIngredient: null,
editedIngredientIndex: -1
}
default: default:
return state; return state;
} }

+ 17
- 15
src/app/shopping-list/shopping-edit/shopping-edit.component.ts View File

@@ -4,8 +4,8 @@ import { Subscription } from 'rxjs/Subscription';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';


import { Ingredient } from '../../shared/ingredient.model'; import { Ingredient } from '../../shared/ingredient.model';
import { ShoppingListService } from '../shopping-list.service';
import * as ShoppingListActions from '../ngrx/shopping-list.actions'; import * as ShoppingListActions from '../ngrx/shopping-list.actions';
import * as fromShoppingList from '../ngrx/shopping-list.reducers';


@Component({ @Component({
selector: 'app-shopping-edit', selector: 'app-shopping-edit',
@@ -16,22 +16,23 @@ export class ShoppingEditComponent implements OnInit, OnDestroy {
@ViewChild('f') shoppingListForm: NgForm; @ViewChild('f') shoppingListForm: NgForm;
subscription: Subscription subscription: Subscription
editMode = false; editMode = false;
editedItemIndex: number;
editedItem: Ingredient; editedItem: Ingredient;


constructor(private shoppingListService: ShoppingListService,
private store: Store<{shoppingList: {ingredients: Ingredient[]}}>) { }
constructor(private store: Store<fromShoppingList.AppState>) { }


ngOnInit() { ngOnInit() {
this.subscription = this.shoppingListService.startedEditing.subscribe(
(index: number) => {
this.editedItemIndex = index;
this.editMode = true;
this.editedItem = this.shoppingListService.getIngredient(index);
this.shoppingListForm.setValue({
name: this.editedItem.name,
amount: this.editedItem.amount
})
this.subscription = this.store.select('shoppingList').subscribe(
data => {
if (data.editedIngredientIndex > -1) {
this.editedItem = data.editedIngredient;
this.editMode = true;
this.shoppingListForm.setValue({
name: this.editedItem.name,
amount: this.editedItem.amount
})
} else {
this.editMode = false;
}
} }
); );
} }
@@ -40,7 +41,7 @@ export class ShoppingEditComponent implements OnInit, OnDestroy {
const value = form.value const value = form.value
const newIngredient = new Ingredient(value.name, value.amount); const newIngredient = new Ingredient(value.name, value.amount);
if (this.editMode) { if (this.editMode) {
this.shoppingListService.updateIngredient(this.editedItemIndex, newIngredient);
this.store.dispatch(new ShoppingListActions.UpdateIngredient(newIngredient));
} else { } else {
this.store.dispatch(new ShoppingListActions.AddIngredient(newIngredient)); this.store.dispatch(new ShoppingListActions.AddIngredient(newIngredient));
} }
@@ -54,11 +55,12 @@ export class ShoppingEditComponent implements OnInit, OnDestroy {
} }


onDelete() { onDelete() {
this.shoppingListService.deleteIngredient(this.editedItemIndex);
this.store.dispatch(new ShoppingListActions.DeleteIngredient());
this.onClear(); this.onClear();
} }


ngOnDestroy() { ngOnDestroy() {
this.store.dispatch(new ShoppingListActions.StopEdit());
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
} }

+ 4
- 4
src/app/shopping-list/shopping-list.component.ts View File

@@ -3,7 +3,8 @@ import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';


import { Ingredient } from '../shared/ingredient.model'; import { Ingredient } from '../shared/ingredient.model';
import { ShoppingListService } from './shopping-list.service';
import * as ShoppingListActions from './ngrx/shopping-list.actions';
import * as fromShoppingList from './ngrx/shopping-list.reducers';


@Component({ @Component({
selector: 'app-shopping-list', selector: 'app-shopping-list',
@@ -13,14 +14,13 @@ import { ShoppingListService } from './shopping-list.service';
export class ShoppingListComponent implements OnInit { export class ShoppingListComponent implements OnInit {
shoppingListState: Observable<{ingredients: Ingredient[]}>; shoppingListState: Observable<{ingredients: Ingredient[]}>;


constructor(private shoppingListService: ShoppingListService,
private store: Store<{shoppingList: {ingredients: Ingredient[]}}>) { }
constructor(private store: Store<fromShoppingList.AppState>) { }


ngOnInit() { ngOnInit() {
this.shoppingListState = this.store.select('shoppingList'); this.shoppingListState = this.store.select('shoppingList');
} }


onEditItem(index: number) { onEditItem(index: number) {
this.shoppingListService.startedEditing.next(index);
this.store.dispatch(new ShoppingListActions.StartEdit(index));
} }
} }

+ 0
- 27
src/app/shopping-list/shopping-list.service.ts View File

@@ -1,27 +0,0 @@
import { Ingredient } from "../shared/ingredient.model";
import { Subject } from "rxjs/Subject";

export class ShoppingListService {
ingredientsChanged = new Subject<Ingredient[]>();
startedEditing = new Subject<number>();
private ingredients: Ingredient[] = [];
getIngredient(index: number) {
return this.ingredients[index];
}

addIngredients(ingredients: Ingredient[]) {
this.ingredients.push(...ingredients);
this.ingredientsChanged.next(this.ingredients.slice());
}

updateIngredient(index: number, newIngredient: Ingredient) {
this.ingredients[index] = newIngredient;
this.ingredientsChanged.next(this.ingredients.slice());
}

deleteIngredient(index: number) {
this.ingredients.splice(index, 1);
this.ingredientsChanged.next(this.ingredients.slice());
}
}

Loading…
Cancel
Save