#javascript #angular #ngrx
#javascript #угловой #ngrx
Вопрос:
cart.service.ts
import { Tools } from './tools';
import { Cart, cartSelector } from './../_store/state/cart/cart.state';
import {
AddProduct,
RemoveProduct,
AddMultiple,
CartMsg,
TypeMessageAlreadyCart,
TypeEmptyCart,
AddAdress,
UpdateProduct
} from './../_store/state/cart/cart.actions';
import { CartItem, Variant } from './../_store/models/cart-item.model';
import { Store } from '@ngrx/store';
import { Injectable, OnDestroy } from '@angular/core';
import { RootState } from '../_store/state/root/root.state';
import { Product } from 'src/app/pages/_model/product.model';
import { Subscription } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class CartService implements OnDestroy {
products: CartItem[];
cartStoreId = 'cart';
idAddress = 0;
subscription = new Subscription();
constructor(
private store: Store<RootState>,
private tools: Tools,
) {
// this.tools.storeInfo({}, this.cartStoreId); // Line to debug Cart
this.recoverCartInfo();
const select = this.store.select(cartSelector).subscribe(
cart => {
this.products = JSON.parse(JSON.stringify(cart.products));
this.idAddress = cart.idAddress;
});
this.subscription.add(select);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
storeCartInfo() {
const cartStored = {
products: this.products,
idAddress: this.idAddress
};
this.tools.storeInfo(cartStored, this.cartStoreId);
}
updateCartPrices(idProduct: number, variants) {
let idx = this.tools.findProduct(idProduct, this.products);
if (idx !== -1) {
let total = 0;
this.products[idx].variants.forEach(variant => {
for (let item of variants) {
if (variant.idVariant === item.ID_VARIANT) {
variant.unitPrice = item.PRICE;
total = variant.unitPrice * variant.qty;
continue;
}
}
})
this.products[idx].totalPrice = total;
}
//this.store.dispatch(new UpdateProduct(this.products));
this.storeCartInfo();
}
recoverCartInfo() {
const cart = this.tools.getInfo(this.cartStoreId);
if (cart amp;amp; (cart.products) amp;amp; (cart.products.length > 0)) {
const result: Cart = {
totalProducts: cart.products.length,
idAddress: cart.idAddress,
products: cart.products,
msgType: '',
currency: this.tools.getInfo('currency_default')
};
this.store.dispatch(new AddMultiple(result));
}
}
addProductToCart(product: Product, variants?: Variant[]) {
if (this.changeProductInCart(product, variants)) {
this.store.dispatch(new AddProduct(this.products));
this.storeCartInfo();
return true;
} else {
this.store.dispatch(new TypeMessageAlreadyCart());
return false;
}
}
changeProductInCart(product: Product, variants?: Variant[]) {
const index = this.tools.findProduct(product.ID_PRODUCT, this.products);
const attrAdded = (variants amp;amp; (variants.length > 0)) ? this.mergeVariantsCart(product.ID_PRODUCT, variants) : [];
const totals = this.counterTotals(attrAdded);
if (index === - 1) {
const item = {
idProduct: product.ID_PRODUCT,
reference: product.REFERENCE,
idProductImage: (product.ID_PRODUCT_IMAGE) ? product.ID_PRODUCT_IMAGE : 0,
name: product.NAME,
totalQty: totals.tQty,
totalPrice: totals.tPrice,
variants: attrAdded
};
this.products.push(item);
return true;
} else if (variants amp;amp; (variants.length > 0)) {
this.products[index].variants = attrAdded;
this.products[index].totalQty = totals.tQty;
this.products[index].totalPrice = totals.tPrice;
return true;
}
return false;
}
mergeVariantsCart(idProduct: number, variants: Variant[]) {
if (this.products.length > 0) {
const index = this.tools.findProduct(idProduct, this.products);
if (index >= 0) {
const varInCart = this.products[index].variants;
if (varInCart.length > 0) {
variants.forEach(variant => {
const idx = this.tools.findVariant(variant.idVariant, varInCart);
if (variant.qty > 0) {
if (idx >= 0) {
varInCart[idx].qty = variant.qty;
varInCart[idx].unitPrice = variant.unitPrice;
} else {
varInCart.push(variant);
}
} else if (idx >= 0) {
varInCart.splice(idx, 1);
}
});
} else {
variants.forEach(variant => {
if (variant.qty > 0) {
varInCart.push(variant);
}
});
}
return varInCart;
} else {
return variants;
}
} else {
return variants;
}
}
counterTotals(variants: Variant[]) {
let totalQty = 0;
let totalPrice = 0;
if (!this.tools.isArrayEmpty(variants)) {
variants.forEach(variant => {
totalQty = (variant.qty * 1);
totalPrice = (variant.qty * variant.unitPrice);
});
}
return {
tQty : totalQty,
tPrice: totalPrice
};
}
addMultipleProductsToCart(products: any[]) {
let added = false;
products.forEach(p => {
if (this.changeProductInCart(p.product, p.variants)) {
added = true;
}
});
if (added) {
const result: Cart = {
totalProducts: this.products.length,
idAddress: this.idAddress,
products: this.products,
msgType: CartMsg.msgOk,
currency: this.tools.getInfo('currency_default')
};
this.store.dispatch(new AddMultiple(result));
this.storeCartInfo();
return true;
} else {
this.store.dispatch(new TypeMessageAlreadyCart());
}
return false;
}
removeProductFromCart(id: number) {
if (this.products.length > 0) {
const index = this.tools.findProduct(id, this.products);
if (index >= 0) {
this.products.splice(index, 1);
this.store.dispatch(new RemoveProduct(this.products));
this.storeCartInfo();
return true;
}
} else {
this.store.dispatch(new TypeEmptyCart());
}
return false;
}
destroyCart() {
this.products = [];
const cart: Cart = {
totalProducts: 0,
idAddress: 0,
products: this.products,
msgType: '',
currency: this.tools.getInfo('currency_default')
};
this.store.dispatch(new AddMultiple(cart));
this.storeCartInfo();
}
addAddress(idAddress: number) {
this.idAddress = idAddress;
this.store.dispatch(new AddAdress(idAddress));
this.storeCartInfo();
}
}
variant-selector.ts
import { Tools } from './../../../../core/_services/tools';
import { CONFIG } from './../../../../app.config';
import {
Component,
Input,
Output,
EventEmitter,
Renderer2,
ElementRef,
ViewChild,
OnChanges,
AfterViewInit,
OnDestroy
} from '@angular/core';
import { Variant } from 'src/app/core/_store/models/cart-item.model';
import { ResponsiveService } from 'src/app/core/_services/resposive.service';
import { Subscription, Observable } from 'rxjs';
import { Store } from '@ngrx/store';
import { RootState } from 'src/app/core/_store/state/root/root.state';
import {
hidePricesSelector,
hideNoStockSelector
} from 'src/app/core/_store/state/config/config.state';
import { UpdateProduct } from 'src/app/core/_store/state/cart/cart.actions';
import { CartService } from 'src/app/core/_services/cart.service';
@Component({
selector: 'b2b-variants-selector',
templateUrl: './variants-selector.component.html'
})
export class VariantsSelectorComponent
implements OnChanges, AfterViewInit, OnDestroy {
@Input() idProduct: number;
@Input() variants: any[];
@Input() variantsInCart: Variant[];
@Input() attributes: any[];
@Input() reference: string;
@Input() isCheckout: boolean;
@Output() variantChange = new EventEmitter<Variant>();
@Output() getValue = new EventEmitter<any>();
@ViewChild('attTable') attTable: ElementRef;
@ViewChild('variantTable') variantTable: ElementRef;
showMatrix = CONFIG.showMatrix;
pricesBySize = CONFIG.pricesBySize;
colors: any;
sizes: any;
tableRealWidth = 0;
tableRotate = 0;
hideArrows = false;
variantSelected: any;
groupSelection: any[] = [];
imgPrd = CONFIG.productImg;
subscription = new Subscription();
private hidePrices$: Observable<boolean>;
private hideNoStock$: Observable<boolean>;
constructor(
private tools: Tools,
private renderer: Renderer2,
private responsiveService: ResponsiveService,
private store: Store<RootState>,
private cartService: CartService
) {
const getRes = this.responsiveService
.getResponsiveDeviceStatus$()
.subscribe(() => this.checkVisibility());
this.subscription.add(getRes);
this.hidePrices$ = this.store.select(hidePricesSelector);
this.hideNoStock$ = this.store.select(hideNoStockSelector);
}
ngOnInit() {
this.cartService.updateCartPrices(this.idProduct,this.variants);
}
ngOnChanges() {
if (this.showMatrix amp;amp; this.attributes.length !== 0) {
this.calculateMatrixAttrs();
}
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
ngAfterViewInit() {
setTimeout(() => {
this.checkVisibility();
}, 10);
}
checkColourOutofStock(color) {
for (const size of this.sizes.ATTR_VALUES) {
const variant = this.getVariant(
this.colors.ID_ATTRIBUTE_GROUP
'-'
color.ID_ATTRIBUTE
'-'
this.sizes.ID_ATTRIBUTE_GROUP
'-'
size.ID_ATTRIBUTE
);
if (
variant amp;amp;
(variant.OUT_OF_STOCK === true ||
variant.QUANTITY > 0 ||
variant.QUANTITY_PRODUCTION > 0)
) {
return false;
}
}
return true;
}
calculateMatrixAttrs() {
this.attributes.forEach((attrGroup: any) => {
if (attrGroup.IS_COLOR_GROUP) {
for (const item of attrGroup.ATTR_VALUES) {
item.ACTIVE = false;
}
this.colors = attrGroup;
} else {
this.sizes = attrGroup;
this.tableRealWidth =
this.tools.getObjectLength(this.sizes.ATTR_VALUES) *
(this.pricesBySize ? 75 : 115)
45;
}
});
}
getMatrixPrice(attrIds: string) {
const variant = this.getVariant(attrIds);
return variant.PRICE;
}
getMatrixDiscount(attrIds: string) {
const variant = this.getVariant(attrIds);
return variant.DISCOUNT ? variant.DISCOUNT : null;
}
getMatrixDiscountType(attrIds: string) {
const variant = this.getVariant(attrIds);
return variant.DISCOUNT_TYPE ? variant.DISCOUNT_TYPE : null;
}
checkVisibility() {
const visibleWidth = this.attTable.nativeElement.offsetWidth - 80;
if (visibleWidth > this.tableRealWidth) {
this.hideArrows = true;
} else {
this.hideArrows = false;
}
}
rotateTable(direction: string) {
const visibleWidth = this.attTable.nativeElement.offsetWidth - 95;
if (visibleWidth < this.tableRealWidth) {
let move = this.tableRotate;
if (direction === 'left') {
move = 240;
if (move > 0) {
move = 0;
}
} else {
const offsetRigth = visibleWidth - this.tableRealWidth;
move -= 240;
if (move < offsetRigth) {
move = offsetRigth;
}
}
this.tableRotate = move;
this.renderer.setStyle(
this.variantTable.nativeElement,
'transform',
'translate3d(' this.tableRotate 'px, 0px, 0px)'
);
}
}
findGroup(id: number) {
if (!this.tools.isArrayEmpty(this.groupSelection)) {
for (let i = 0; i < this.groupSelection.length; i ) {
if (this.groupSelection[i].idGroup === id) {
return i;
}
}
}
return -1;
}
checkSelected(groupId: number, variantId: number) {
const idx = this.findGroup(groupId);
if (idx >= 0 amp;amp; this.groupSelection[idx].idVariant === variantId) {
return true;
}
return false;
}
changeVariantSelection(groupId: number, variantId: number) {
const idx = this.findGroup(groupId);
if (idx === -1) {
this.groupSelection.push({
idGroup: groupId,
idVariant: variantId
});
} else {
this.groupSelection[idx].idVariant = variantId;
}
this.getVariantSelected();
}
getVariantSelected() {
const sortGroup = this.groupSelection.sort((a, b) =>
a.idGroup > b.idGroup ? 1 : -1
);
let hassIds = '';
let counter = 0;
sortGroup.forEach(g => {
if (counter > 0) {
hassIds = '-';
}
hassIds = g.idGroup '-' g.idVariant;
counter ;
});
this.variantSelected = this.getVariant(hassIds);
}
sendVariantAdded(variant: Variant) {
this.variantChange.next(variant);
}
getQtyincart(idVariant: number) {
const idx = this.tools.findVariant(idVariant, this.variantsInCart);
return idx >= 0 ? this.variantsInCart[idx].qty : 0;
}
getVariant(attrIds: string) {
let variantData = null;
this.variants.forEach(variant => {
if (variant.ATTRIDS === attrIds) {
variantData = { ...variant };
variantData.qtyIncArt = this.getQtyincart(variantData.ID_VARIANT);
}
});
return variantData;
}
changeImage(color, active) {
const tempActive = active;
let init = false;
for (const item of this.colors.ATTR_VALUES) {
item.ACTIVE = false;
}
if (this.colors.ATTR_VALUES.find(x => x.ATTR_REFERENCE === color)) {
if (tempActive) {
this.colors.ATTR_VALUES.find(
x => x.ATTR_REFERENCE === color
).ACTIVE = false;
init = true;
} else if (
this.colors.ATTR_VALUES.find(x => x.ATTR_REFERENCE === color)
.IMAGES[0] !== ''
) {
this.colors.ATTR_VALUES.find(
x => x.ATTR_REFERENCE === color
).ACTIVE = true;
}
}
this.getValue.emit({ color, init });
}
}
В приведенном выше коде я пытаюсь вызвать функцию updateCartPrices
, но она переходит в бесконечный цикл из-за отправки комментариев. Я новичок в angular, и было бы здорово, если бы вы помогли мне решить эту проблему
Я думаю, проблема в том, что при обновлении состояния происходит перезагрузка представления, я не понимаю, почему