2017年1月10日 星期二

[Angular] Redux with ngrx/store – Shopping cart sample (2)

 Angular     ngrx      ngrx/store     Redux  




Introduction


In the previous practice, we had successfully created an Angular app with ngrx/store to keep the shopping cart state in our application.

Let’s improve the application by storing the individual product’s information in the state, and therefore we can show what a user are going to buy from the shopping cart.


Source code



Related articles




Environment


Angular 5.2.0

@ngrx/store  5.2.0




Implement


Update state class


ShopCart.ts

Add a new property, ShopItem[] array into the ShopCart class.

import { IShopCart } from '../interface/IShopCart';
import { ShopItem } from '../class/ShopItem';

export class ShopCart implements IShopCart {
    items: ShopItem[];
    cnt: number;
    sum: number;

    constructor() {
        this.items = [];
        this.cnt = 0;
        this.sum = 0;
    }
}




ShopItem.ts

Also we should keep the id and title of the item we put in the shopping cart.

export class ShopItem {
    id: string; //Product ID
    title: string; //Product name
    count: number; //Counter
    price: number; //Cash summary
    public constructor(
        fields?: {
            id?: string,
            title?: string,
            count?: number,
            price?: number
        }) {
        if (fields) {
            Object.assign(this, fields);
        } else {
            this.count = 0;
            this.price = 0;
        }
    }
}


Update reducer

We should implement the following logic in actions.

1.When pushing an item into the shopping cart,
  1-1. If the item is first time being push, add it to the state.
  1-2. Or update the count of the item in the state.

2.When pulling an item from the shopping cart,
  2-1. Update the count of the item in the state.
  2-2. Check if the item’s count equals zero, if yes, remove the item from the state.

shopcart.action.ts

export const PUSH = 'PUSH';
export const PULL = 'PULL';
export const CLEAR = 'CLEAR';

export function shopcartReducer(state: ShopCart = new ShopCart(), action: ShopcartAction) {
    switch (action.type) {
        case PUSH:
            return pushToCart(state, action.payload);

        case PULL:
            return pullFromCart(state, action.payload);

        case CLEAR:
            state.cnt = 0;
            state.sum = 0;
            state.items = [];
            return state;

        default:
            return state;
    }
}

function pushToCart(shopcart: ShopCart, payload: ShopItem):ShopCart {
    shopcart.cnt += 1;
    shopcart.sum += payload.price * 1;
    updateItems(shopcart, payload);
    return shopcart;


}
function pullFromCart(shopcart: ShopCart, payload: ShopItem): ShopCart {
    shopcart.cnt -= 1;
    shopcart.sum -= payload.price * 1;
    updateItems(shopcart, payload);
    return shopcart;


}
function updateItems(shopcart: ShopCart, payload: ShopItem) {
    let targetItem = shopcart.items.find(item => item.id === payload.id);
    if (targetItem) { //Exist
        if (payload.count <= 0) {
            var index = shopcart.items.indexOf(targetItem);
            shopcart.items.splice(index, 1);
        }
        else {
            targetItem.count = payload.count;
        }
    }
    else { //First time adding to shopping cart
        shopcart.items.push(payload);
    }


}


Okay, it’s done. We have successfully made the state supports keeping the individual product information.



Using the current state


We will use the current state to get the items in the shopping cart, and then update the display value in the view.  





Take ProductBooksComponent for example,


product-books.component.ts (Update)

ngOnInit() {
        this.initBooks();
    }
//Initialize books
    private initBooks() {
        this.productService.getByType(PROD_TYPE).subscribe(data => {
            this.books = data;

            //Use shopping cart to update data
            this.shopcart$.subscribe(cart => {
                this.books.forEach(item => {

                    if (cart.items) {
                        let storeItem = cart.items.find(x => x.id === item.id);
                        if (!storeItem) {
                            this.itemNumbers[item.id] = 0;
                        }
                        else {
                            this.itemNumbers[item.id] = storeItem.count;
                        }
                    }
                });
            })

        })
    }

    


Save the state (Shopping cart)

Everything is done for our shopping cart, all we have to do is send the state’s information to backend after user clicks a save button or whatever.

(I will skip this practice, but you can take a deep look at my source code which integrates Firebase … :)





Demo

Sample codes







Reference






沒有留言:

張貼留言