In this part we will continue to build user part.
We are going to create a orders page.
- orders.component.ts
- orders.component.html
- orders.component.css
src/app/ecommerce/orders.component.ts
import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Subscription } from '.rxjs';
import { ProductOrders, User } from 'src/app/modal/Modal';
import { OrderService } from 'src/app/service/order.service';
import { UserService} from 'src/app/service/user.service';
import { UpdateProfileComponent } from 'src/app/update-profile/update-profile.component';
@Component({
selector: 'app-orders',
templateUrl: './orders.component.html',
styleUrls: ['./orders.component.css']
})
export class OrdersComponent implements OnInit {
orders: ProductOrders;
user: User = new User();
total: number;
paid: false;
sub = Subscription;
hideUpdateMessage = true;
id: number;
name: string;
username: string;
email: string;
password: string;
nameOnCard: string;
cardNumber: string;
cvv: number;
address: string;
errorMessage: string;
hideDiv = true;
newDate: Date;
hideItem: boolean;
constructor(private orderService: OrderService, private userService: UserService, private dialog: MatDialog) {
this.orders = this.orderService.ProductOrders;
}
ngOnInit() {
this.userService.findByUsername(this.userService.getUsername()).subscribe(user => {
this.user = user;
if (this.nameOnCard != null || this.cardNumber || this.cvv || this.address) {
this.nameOnCard = this.user.nameOnCard;
this.cardNumber = this.user.cardNumber;
this.cvv = this.user.cvv;
this.address = this.user.address;
}
})
this.sub = this.orderService.OrdersChanged.subscribe(() => {
this.orders = this.orderService.ProductOrders;
});
this.loadTotal();
this.newDate = new Date();
}
pay() {
this.paid = true;
this.hideDiv = false;
this.orderService.saveOrder(this.orders).subscribe();
}
loadTotal() {
this.sub = this.orderService.TotalChanged.subscribe(() => {
this.total = this.orderService.Total;
});
}
goToHome() {
window.location.reload();
}
goToUpdateProfile(idUser) {
this.hideUpdateMessage = false;
this.dialog.open(UpdateProfileComponent, {
data: { idUser }
})
}
}
src/app/ecommerce/orders.component.html
<div *ngIf="(user | json) != '{}' || user.nameOnCard || user.address || user.cardNumber || user.email || user.cvv; else loggedOut">
<div class="columns" *ngIf="hideDiv">
<div id="cart-imgs" *ngIf="!paid">
<div>
<a> <img class="img-thumbnail"
src="http://www.pret-pas-cher.fr/wp-content/uploads/2015/01/carte-mastercard.png">
</a>
</div>
<div>
<a><img class="img-thumbnail"
src="https://www.techno-finance.fr/wp-content/uploads/2018/10/2000px-Visa_Electron.svg.png">
</a>
</div>
</div>
<h2 class="text-center" *ngIf="!paid" role="alert" class="alert alert-primary">ORDER</h2>
<ul *ngIf="!paid" id="bill">
<li *ngFor="let order of orders.productOrders">
{{ order.product.name }} - ${{ order.product.price }} x {{ order.quantity}} pcs.
</li>
</ul>
<p role="alert" class="alert alert-danger" *ngIf="!paid">Total amount: ${{ total }}</p>
<button class="btn btn-primary btn-block" (click)="pay()" *ngIf="!paid">Pay</button>
</div>
<div *ngIf="paid">
<div class="columns">
<ul class="price">
<li class="header" role="alert" class="alert alert-success" style="margin-bottom: 1px;">
<strong>Congratulation!</strong> You successfully made the order. <strong>Bill is</strong>
</li>
<li class="grey" style="color: #c0392b">Total amount: ${{ total }} With delivry</li>
<li> {{newDate | date: 'yyyy-MM-dd hh:mm' }} </li>
<li class="grey" style="cursor: pointer; color: #FFF"><a (click)="goToHome()" class="button">Finished</a></li>
</ul>
</div>
</div>
</div>
<ng-template #loggedOut>
<div class="alert alert-warning" style="margin-top: 15px;" *ngIf="hideUpdateMessage">
<strong>You must update your profile!</strong> To complete your chopping.
<button class="btn btn-success" (click)="goToUpdateProfile(user.id)">Update</button>
</div>
</ng-template>
src/app/ecommerce/orders.component.css
.container {
padding-top: 65px;
}
#cart-imgs {
display: flex;
margin-top: 10px;
padding-left: 42px;
}
#cart-imgs img {
height: 120px;
width: 250px;
margin-left: 10px;
}
* {
box-sizing: border-box;
}
#bill {
border: 1px solid #f0f0f0;
padding: 10px 24px;
color: #2c3e50;
margin: 0px !important;
}
.columns {
float: left;
width: 100%;
margin-left: 4px;
background: antiquewhite;
padding: 10px;
margin-top: 20px;
border-radius: 5px;
}
.price {
list-style-type: none;
border: 1px solid #eee;
margin: 0;
padding: 0;
-webkit-transition: 0.3s;
transition: 0.3s;
}
.price:hover {
box-shadow: 0 8px 12px 0 rgba(0, 0, 0, 0.2);
}
.price .header {
font-size: 25px;
}
.price li {
border-bottom: 1px solid #eee;
padding: 20px;
text-align: center;
}
.price .grey {
background-color: #ecf0f1;
font-size: 20px;
}
.button {
background-color: #4caf50;
border: none;
color: white;
padding: 10px 25px;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
}
@media only screen and ( max-width: 600px) {
.columns {
width: 100%;
}
}
.alert-primary {
margin: 20px 0px 0px 0px !important;
}
.alert-danger {
margin: 0px !important;
}
We are going to create a products page.
- products.component.ts
- products.component.html
- products.component.css
src/app/ecommerce/products.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { User,ProductOrder, Product, ProductOrders } from '../model/Model';
import { MatDialog } from '@angular/material/dialog';
import { LoginComponent } from 'src/app/login/login.component';
import { OrderService } from 'src/app/service/order.service';
import { ProductService } from 'src/app/service/product.service';
import { UserService } from 'src/app/service/user.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
productOrders: ProductOrder[] = [];
products: Product[] = [];
user: User = new User();
selectedProductOrder: ProductOrder;
shoppingCartOrders: ProductOrders;
sub: Subscription;
productSelected = false;
description: string;
showMyContainerInfo = false;
showBtn = -1;
idCart: number;
constructor(private orderService: OrderService, private router: Router, private dialog: MatDialog,
private productService: ProductService, private userService: UserService) {
this.userService.findByUsername(this.userService.getUsername()).subscribe(user => {
this.user = user;
});
}
ngOnInit(): void {
this.productOrders = [];
this.loadProducts();
this.loadOrders();
}
addToCart(order: ProductOrder, idUser) {
this.orderService.SelectedProductOrder = order;
this.selectedProductOrder = this.orderService.SelectedProductOrder;
this.productSelected = true;
}
removeFromCart(productOrder: ProductOrder, idUser) {
let index = this.getProductIndex(productOrder.product);
if (index > -1) {
this.shoppingCartOrders.productOrders.splice(
this.getProductIndex(productOrder.product), 1);
}
this.orderService.ProductOrders = this.shoppingCartOrders;
this.shoppingCartOrders = this.orderService.ProductOrders;
this.productSelected = false;
}
getProductIndex(product: Product): number {
return this.orderService.ProductOrders.productOrders.findIndex(
value => value.product === product);
}
isProductSelected(product: Product): boolean {
return this.getProductIndex(product) > -1;
}
loadProducts() {
this.productService.findAllProducts().subscribe(
(products: any[]) => {
this.products = products;
this.products.forEach(product => {
this.productOrders.push(new ProductOrder(product, 0));
})
}
);
}
src/app/ecommerce/products.component.html
<div class="row card-deck">
<div class="col-lg-4 col-md-6 mb-4" *ngFor="let order of productOrders; let i = index">
<div class="card text-center">
<div class="card-header" style="background-color: #bdc3c7">
<h4>{{ order.product.name }}</h4>
</div>
<div class="card-body">
<a (click)="sngleProduct(order.product.id)"><img class="card-img-top img-thumbnail"
style="width: 230px; height: 300px; cursor: pointer" src="{{ order.product.pictureUrl }}" alt="image" /></a>
<h5 class="card-title" id="price">
Price = {{ order.product.price }}<i class="fas fa-dollar-sign"></i>
<button title="Information" id="btn" (click)="showUndoBtn(i)" (click)="productInfo(order.product.id)">
<i class="fas fa-info-circle"></i>
</button>
<button title="View" id="btn" (click)="sngleProduct(order.product.id)">
<i class="fas fa-eye-slash"></i>
</button>
</h5>
<div class="modal" [attr.id]="'undoBtn' + i" *ngIf="showBtn === i && showMyContainerInfo" class="editBtn"
md-raised-button color="primary">
<div class="modal-content">
<span>{{ description }}</span>
</div>
</div>
<hr style="margin-top: 0px !important; margin-bottom: 10px !important"/>
<div class="row" *ngIf="user">
<div class="col-5 padding-0" *ngIf="!isProductSelected(order.product)" style="margin-left: 15px">
<input type="number" min="0" max="10" class="form-control" [(ngModel)]="order.quantity"/>
</div>
<div class="col-5 padding-0" *ngIf="!isProductSelected(order.product)">
<button class="btn btn-primary" (click)="addToCart(order)" [disabled]="order.quantity <= 0">
Puy Now
</button>
</div>
<div class="col-12" *ngIf="isProductSelected(order.product)">
<button class="btn btn-danger btn-block active" (click)="removeFromCart(order)">
Remove From Cart
</button>
</div>
</div>
<div *ngIf="!user">
<p><strong>Please login to buy product</strong> <button type="button" class="btn btn-link"
(click)="login()">Login</button> </p>
</div>
</div>
</div>
</div>
</div>
We are going to create a sangle-product page.
- sangle-product.component.ts
- sangle-product.component.html
- sangle-product.component.scss
src/app/ecommerce/sangle-product.component.ts
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ProductOrder, Product, ProductOrders, UpdateProduct, Tag, User, Comment, Cart } from '../model/Model';
import { Subscription } from 'rxjs';
import { LoginComponent } from 'src/app/login/login.component';
import { CartService } from 'src/app/service/cart.service';
import { CommentService } from 'src/app/service/comment.service';
import { OrderService } from 'src/app/service/order.service';
import { ProductService } from 'src/app/service/product.service';
import { TagService } from 'src/app/service/tag.service';
import { UserService } from 'src/app/service/user.service';
import { OrdersComponent } from '../orders/orders.component';
import { ShoppingCartComponent } from '../shopping-cart/shopping-cart.component';
@Component({
selector: 'app-sangle-product',
templateUrl: './sangle-product.component.html',
styleUrls: ['./sangle-product.component.scss']
})
export class HomeComponent implements OnInit {
productOrders: ProductOrder[] = [];
products: Product[] = [];
tags: Tag[] = [];
comments: Comment[] = [];
user: User = {} as User;
comment: Comment = {} as Comment;
cartExist: Cart = {} as Cart;
cart: Cart = {} as Cart;
name: string;
selectedProductOrder: ProductOrder;
shoppingCartOrders: ProductOrders;
sub: Subscription;
productSelected = false;
collapsed = true;
orderFinished = false;
showBtn = -1;
submitted: false;
idProduct: number;
product: UpdateProduct;
@ViewChild('shoppingCartC')
shoppingCartC: ShoppingCartComponent;
@ViewChild('ordersC')
ordersC: OrdersComponent;
description: string = '';
showMyContainerInfo = false;
counter: number = 1;
@Input() url = location.href;
constructor(private productService: ProductService, private tagService: TagService,
private orderService: OrderService, private route: ActivatedRoute, private userService: UserService,
private commentService: CommentService, private dialog: MatDialog,
private cartService: CartService) {
}
ngOnInit(): void {
this.loadOrders();
this.sangleProduct();
this.userService.findByUsername(this.userService.getUsername()).subscribe(user => {
this.user = user;
})
}
addToCart(order: ProductOrder, idUser) {
this.orderService.SelectedProductOrder = order;
this.selectedProductOrder = this.orderService.SelectedProductOrder;
this.productSelected = true;
this.cart.name = order.product.name;
this.cart.price = order.product.price;
this.cart.quantity = order.quantity;
this.cart.pictureUrl = order.product.pictureUrl;
this.cartService.addCartToUser(this.cart, idUser).subscribe(cart => {
this.cart = cart;
this.cartService.saveCartName(this.cart.name);
})
}
removeFromCart(productOrder: ProductOrder, idUser) {
let index = this.getProductIndex(productOrder.product);
if (index > -1) {
this.shoppingCartOrders.productOrders.splice(
this.getProductIndex(productOrder.product), 1);
const name = this.cartService.getCartName();
this.cartService.findCartsForUser(idUser).subscribe(carts => {
this.cartExist = carts.filter(item => item.name === name)[0];
this.cartService.removeFromCart(this.cartExist.id, idUser).subscribe(() => {
})
})
}
this.orderService.ProductOrders = this.shoppingCartOrders;
this.shoppingCartOrders = this.orderService.ProductOrders;
this.productSelected = false;
}
getProductIndex(product: Product): number {
return this.orderService.ProductOrders.productOrders.findIndex(
value => value.product === product);
}
isProductSelected(product: Product): boolean {
return this.getProductIndex(product) > -1;
}
loadOrders() {
this.sub = this.orderService.OrdersChanged.subscribe(() => {
this.shoppingCartOrders = this.orderService.ProductOrders;
});
}
toggleCollapsed(): void {
this.collapsed = !this.collapsed;
}
finishOrder(orderFinished: boolean) {
this.orderFinished = orderFinished;
}
reset() {
this.productOrders = [];
this.orderService.ProductOrders.productOrders = [];
this.loadOrders();
this.productSelected = false;
this.orderFinished = false;
this.shoppingCartC.reset();
this.ordersC.paid = false;
}
private sangleProduct() {
this.product = new UpdateProduct();
this.idProduct = this.route.snapshot.params.idProduct;
this.tagService.findTagsForProduct(this.idProduct).subscribe(tags => {
this.tags = tags;
});
this.commentService.findCommentsForProduct(this.idProduct).subscribe(comments => {
this.comments = comments;
});
this.productService.findProductById(this.idProduct).subscribe(data => {
this.name = data.name;
this.productService.findByName(this.name).subscribe((products: any[]) => {
this.products = products;
this.products.forEach(product => {
this.productOrders.push(new ProductOrder(product, 0));
});
});
this.submitted = true;
});
}
addComment(idProduct, username) {
this.comment.addedBy = username;
this.commentService.addCommentToProduct(this.comment, idProduct).subscribe(comment => {
this.comment = comment;
window.location.reload();
})
}
login() {
this.dialog.open(LoginComponent);
}
}
src/app/ecommerce/sangle-product.component.html
<div class="container" *ngFor="let order of productOrders let i = index;">
<div class="row">
<div class="col" [hidden]="orderFinished">
<div class="pricing-table">
<div class="pricing-item pricing-featured">
<div class='selected'>Recomend</div>
<div class="pricing-title">
Product
</div>
<div class="pricing-value">R${{order.product.price}}.<span class="smallText">90</span>
</div>
<ul class="pricing-features">
<li><span class="keywords">Name</span> {{order.product.name}}</li>
<li>Description <br>
<span>
{{order.product.description}}
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nisi hic fugit inventore saepe
optio quidem sunt, molestiae voluptate doloribus accusantium corporis quisquam veritatis
tempora, similique consequuntur distinctio dicta error esse?
</span>
</li>
</ul>
<div class="button" *ngIf="user">
<div *ngIf="!isProductSelected(order.product)">
<button id="addToCartBtn" class="btn-block" (click)="addToCart(order, user.id)">Add To Cart
</button>
</div>
<div *ngIf="isProductSelected(order.product)">
<button class="btn btn-danger btn-block active" (click)="removeFromCart(order, user.id)">Remove From Cart
</button>
</div>
</div>
<div *ngIf="!user">
<p><strong>Please login to buy product</strong> <button type="button" class="btn btn-link"
(click)="login()">Login</button> </p>
</div>
</div>
</div>
</div>
<div class="col" [hidden]="orderFinished">
<img class="card-img-top img-thumbnail" style="width: 100%; height: 570px" src={{order.product.pictureUrl}}
alt="image">
<div *ngIf="!isProductSelected(order.product)">
<input type="hidden" tabindex="0" min="1" max="1" class="form-control" [(ngModel)]="order.quantity" />
</div>
<ul class="list-group list-group-horizontal-sm">
<li class="list-group-item" *ngFor="let tag of tags"
style="margin-left: 5px; margin-left: 5px; margin-top: 10px; padding: 5px 10px;">
<a [routerLink]="['/display-tag/', tag.id]" style="cursor: pointer; color: blue;">{{tag.name}}</a>
</li>
</ul>
</div>
<div class="col" style="padding-right: 34px;">
<div style="margin-top: 5px;">
<app-shopping-cart (onOrderFinished)=finishOrder($event) #shoppingCartC [hidden]="orderFinished">
</app-shopping-cart>
</div>
<div>
<app-orders #ordersC [hidden]="!orderFinished"></app-orders>
</div>
</div>
<hr style="border: 1px solid #ddd;">
</div>
</div>
<div class="container" style="margin-bottom: 50px;" [hidden]="orderFinished">
<div class=info-comment">
<p><strong>Comments </strong></p>
</div>
<div class="card col-md-8" *ngIf="user">
<div class="card-body">
<form>
<div class="mb-3">
<input type="text" class="form-control" placeholder="Title" name="title" [(ngModel)]="comment.title">
</div>
<div class="mb-3">
<textarea class="form-control" rows="3" placeholder="Message" name="message"
[(ngModel)]="comment.message"></textarea>
</div>
<a (click)="addComment(idProduct, user.username)" class="btn btn-primary">Add comment</a>
</form>
</div>
</div>
<div class="card col-md-8" *ngIf="!user">
<div class="card-body">
<div class="info-comment">
<p><strong>Please login to add Comment </strong> <button type="button" class="btn btn-link"
(click)="login()">Login</button> </p>
</div>
</div>
</div>
<div class="container-comment" *ngFor="let item of comments">
<img src="https://png.pngtree.com/png-vector/20190710/ourlarge/pngtree-user-vector-avatar-png-image_1541962.jpg"
alt="Avatar" style="width:90px">
<p><span>{{item.addedBy}}</span> {{item.addedAt | date}}</p>
<p><strong>{{item.title}}: </strong> {{item.message}}</p>
</div>
</div>
src/app/ecommerce/sangle-product.component.scss
*,
*:before,
*:after {
-webkit-box-sizing : border-box ;
-moz-box-sizing : border-box ;
box-sizing : border-box ;
}
html,
body {
height : 100%;
min-height : 100%;
margin : 0;
padding : 0;
}
body {
background-color : #fcfcfc ;
font-family : "Montserrat", sans-serif ;
text-align : center ;
}
.pricing-table {
text-align : center ;
margin-top : -16px;
}
.pricing-item {
border-radius : 3px;
display : inline-block ;
width : 100%;
height : 100%;
background : #fff ;
margin : 20px;
vertical-align : top ;
position : relative ;
overflow : hidden ;
box-shadow : 0 1.5px 4px rgba (0, 0, 0, 0.24), 0 1.5px 6px rgba(0, 0, 0, 0.12);
-webkit-transition : all 0.2s cubic-bezier (0.3, 0.6, 0.2, 1.8);
transition : all 0.2s cubic-bezier (0.3, 0.6, 0.2, 1.8);
&:hove r {
-webkit-transform : scale (1.04);
-ms-transform : scale (1.04);
transform : scale (1.04);
box-shadow : 0 3px 12px rgba (0, 0, 0, 0.23), 0 3px 12px rgba(0, 0, 0, 0.16);
}
.pricing-title {
width : 100%;
color : white ;
display : block ;
position : relative ;
background : #0074d9 ;
padding : 7px;
font-weight : bold;
font-size : 20px;
}
&.pricing-featured .pricing-title {
background : #ff4136 ;
}
}
.pricing-value {
width : 180px;
height : 180px;
padding-top : 46px;
border-radius : 50%;
color : #fff;
font-size : 46px;
font-weight : 300;
margin : 10px auto ;
}
.pricing-value .smallText {
font-size : 14px;
}
.pricing-value .undertext {
display : block ;
font-size : 16px;
}
.pricing-item .pricing-value {
background : #0074d9 ;
border : 2px solid #0074d9 ;
}
.pricing-item.pricing-featured .pricing-value {
background : #ff4136 ;
border : 2px solid #ff4136 ;
}
.pricing-item .pricing-features {
margin: 10px 0;
padding: 0;
list-style: none;
& li {
display: block;
width: 90%;
line-height: 40px;
font-size: 15px;
font-weight: 400;
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
margin: 0 auto;
.keywords {
font-weight: bold;
}
}
}
.button {
width: 160px;
height: 38px;
font-weight: 300;
font-size: 16px;
line-height: 32px;
margin: 0 auto;
background: #fff;
color: #0074d9;
border: 2px solid #0074d9;
cursor: pointer;
margin-bottom: 10px;
-webkit-transition: 0.2s ease-out;
-moz-transition: 0.2s ease-out;
-o-transition: 0.2s ease-out;
-ms-transition: 0.2s ease-out;
transition: 0.2s ease-out;
&:hover {
background: #0074d9;
color: #fff;
border: none;
-webkit-box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18),
0 4px 15px 0 rgba(0, 0, 0, 0.15);
box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18),
0 4px 15px 0 rgba(0, 0, 0, 0.15);
}
}
.pricing-item.pricing-featured .button {
color: #ff4136;
border: 2px solid #ff4136;
&:hover {
background: #ff4136;
color: #fff;
}
}
.selected {
z-index: 10;
width: 180px;
height: 32px;
padding: 0 20px;
font-size: 12px;
line-height: 25px;
text-align: center;
color: #fff;
font-weight: bold;
box-shadow: 0px 2px 5px #888888;
background: gold;
border-top: 5px solid gold;
border-bottom: 5px solid gold;
transform: rotate(35deg);
position: absolute;
right: -47px;
top: 17px;
}
#addToCartBtn {
background: #fff;
border: none;
}
#addToCartBtn:hover {
background: #0074d9;
}
.jumbotron span {
margin-left: 5px;
}
.container {
background: aliceblue;
padding: 10px;
border-radius: 10px;
padding-bottom: 10px;
margin-top: 50px;
}
.info-comment {
background-color: #ffdddd;
border-left: 16px solid #f44336;
border-right: 16px solid #f44336;
margin-bottom: 15px;
padding: 4px 12px;
border-radius: 5px;
}
.container-comment {
border: 2px solid #eee;
background-color: #fff;
border-radius: 5px;
padding: 16px;
margin: 16px 0;
}
.container-comment::after {
content: "";
clear: both;
display: table;
}
.container-comment img {
float: left;
margin-right: 20px;
border-radius: 50%;
}
.container-comment span {
font-size: 20px;
margin-right: 15px;
}
@media ( max-width: 500px) {
.container-comment {
text-align: center;
}
.container-comment img {
margin: auto;
float: none;
display: block;
}
}
We are going to create a shopping-cart page.
- shopping-cart.component.ts
- shopping-cart.component.html
- shopping-cart.component.css
src/app/ecommerce/shopping-cart.component.ts
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { Router } from '@angular/router';
import { ProductOrders, ProductOrder, Item, ITEMS } from '../model/Model';
import { OrderService } from '../service/order.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-shopping-cart',
templateUrl: './shopping-cart.component.html',
styleUrls: ['./shopping-cart.component.css']
})
export class ShoppingCartComponent implements OnInit {
itemsList: Item[] = ITEMS;
orderFinished: boolean;
orders: ProductOrders;
total: number;
sub: Subscription;
radioSel: any;
priceDelivery: number;
radioSelected: string;
radioSelectedString: string;
@Output() onOrderFinished: EventEmitter<boolean>;
constructor(private orderService: OrderService, private router: Router) {
this.total = 0;
this.orderFinished = false;
this.onOrderFinished = new EventEmitter<boolean>();
this.itemsList = ITEMS;
this.radioSelected = 'item_1';
this.getSelecteditem();
}
ngOnInit() {
this.orders = new ProductOrders();
this.loadCart();
this.loadTotal();
this.itemsList.forEach((item) => {
this.onItemChange(item);
});
this.priceDelivery = 1.99;
}
calculateTotal(products: ProductOrder[]): number {
let sum = 0;
products.forEach((value) => {
sum += value.product.price * value.quantity;
});
return sum + this.priceDelivery;
}
ngOnDestroy() {
this.sub.unsubscribe();
}
finishOrder() {
this.orderFinished = true;
this.orderService.Total = this.total;
this.onOrderFinished.emit(this.orderFinished);
}
loadTotal() {
this.sub = this.orderService.OrdersChanged.subscribe(() => {
this.total = this.calculateTotal(this.orders.productOrders);
});
}
loadCart() {
this. sub = this.orderService.ProductOrderChanged.subscribe(() => {
let productOrder = this. orderService.SelectedProductOrder;
if (productOrder) {
this.orders.productOrders.push(
new ProductOrder( productOrder.product, productOrder.quantity)
);
}
this.orderService.ProductOrders = this. orders;
this.orders = this. orderService.ProductOrders;
this.total = this. calculateTotal(this.orders.productOrders);
});
}
reset() {
this.orderFinished = false;
this.orders = new ProductOrders();
this.orders. productOrders = [];
this.loadTotal();
this. total = 0;
}
getSelecteditem() {
this. radioSel = ITEMS.find(( Item) => Item.value === this. radioSelected);
this. radioSelectedString = JSON.stringify(this.radioSel);
}
onItemChange( item: any) {
this.getSelecteditem();
this.priceDelivery = item.price;
}
}
src/app/ecommerce/shopping-cart.component.html
<div style="background: aliceblue; padding: 10px; border-radius: 5px;">
<div class="card text-white bg-danger mb-3" style="max-width: 19rem;">
<div class="card-header text-center">Shopping Cart</div>
<div class="card-body">
<h5 class="card-title">Total: ${{total}}</h5>
<h6 class="card-title">Items bought</h6>
<ul>
<li *ngFor="let order of orders.productOrders">
{{ order.product.name }} - {{ order.quantity}} pcs.
</li>
</ul>
<button class="btn btn-light btn-block" (click)="finishOrder()"
[disabled]="orders.productOrders.length == 0">Checkout
</button>
</div>
</div>
<div class="card text-white bg-warning mb-3" style="max-width: 19rem;">
<div class="card-header text-center">Delivry</div>
<div class="card-body" style="padding: 0px !important; margin-top: -30px;">
<div class="text-center mt-5" style="text-align: left !important; padding: 0">
<div>
<ul class="list-group" style="color: black">
<li class="list-group-item" *ngFor="let item of itemsList" style="background: #ffc107 !important;">
<input type="radio" [(ngModel)]="radioSelected" name="list_name" value="{{item.value}}"
(change)="onItemChange(item)"/>
{{item.name}}{{item.price}}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
.list-group-item {
background: #007bff !important;
}
.list-group-item a {
color: gold;
}
.fa-comment-dots {
font-size: 100px;
color: #bdc3c7;
}
.fa-comment-dots:hover {
color: #039be6;
}
#social-media-icon {
margin-top: 20px;
width: 120px;
text-align: center;
margin-left: 20px;
border-radius: 10px;
}
#social-media-icon .fa {
padding: 14px;
font-size: 18px;
text-align: center;
text-decoration: none;
margin: 5px 2px;
border-radius: 50%;
}
#social-media-icon .fa:hover {
opacity: 0.7;
}
#social-media-icon .fa-facebook {
background: #3b5998;
color: white;
}
#social-media-icon .fa-twitter {
background: #55acee;
color: white;
}
#social-media-icon .fa-google {
background: #dd4b39;
color: white;
}
#social-media-icon .fa-instagram {
background: #125688;
color: white;
}
We are going to create a ecommerce page.
- ecommerce.component.ts
- ecommerce.component.html
src/app/ecommerce.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { Product } from '../model/Model';
import { ProductService } from '../service/product.service';
import { OrdersComponent } from './orders/orders.component';
import { ProductsComponent } from './products/products.component';
import { ShoppingCartComponent } from './shopping-cart/shopping-cart.component';
@Component({
selector: 'app-ecommerce',
templateUrl: './ecommerce.component.html',
styleUrls: ['./ecommerce.component.css']
})
export class EcommerceComponent implements OnInit {
products: Product[];
product: Product = {} as Product;
orderFinished = false;
name: any;
showSearch = false;
showBtn = -1;
showMyContainerInfo = false;
@ViewChild('productsC')
productsC: ProductsComponent;
@ViewChild('shoppingCartC')
shoppingCartC: ShoppingCartComponent;
@ViewChild('ordersC')
ordersC: OrdersComponent;
constructor(private productService: ProductService, private router: Router) { }
ngOnInit(): void { }
finishOrder(orderFinished: boolean) {
this.orderFinished = orderFinished;
}
reset() {
this.orderFinished = false;
this.productsC.reset();
this.shoppingCartC.reset();
this.ordersC.paid = false;
}
search() {
this.productService.findByName(this.name).subscribe((products) => {
this.products = products;
this.showSearch = true;
});
}
showUndoBtn(index) {
this.showBtn = index;
}
productInfo(id: number) {
this.productService.findProductById(id).subscribe((product) => {
this.product = product;
});
this.showMyContainerInfo = !this.showMyContainerInfo;
}
sngleProduct(id: number) {
this.router.navigate(['sangle/product', id]);
}
}
src/app/ecommerce.component.html
<div class="container" [hidden]="orderFinished">
<div class="row">
<div class="col-lg-4">
< <h2 class="title-page"><i class="fab fa-dropbox"></i> Products <i class="fab fa-dropbox"></i></h2>
</div>
<div class="col-lg-8">
<div class="input-group mb-3" style="margin-top: 15px;">
<input type="text" class="form-control" placeholder="Search product" name="name" [(ngModel)]="name">
<button class="btn btn-danger" type="button" (click)="search()"><i class="fas fa-search"></i></button>
</div>
</div>
</div>
</div>
<hr>
<div class="row" style="padding-bottom: 40px;" *ngIf="!showSearch">
<div class="col-md-9"
<app-products #productsC [hidden]="orderFinished"></app-products>
</div>
élt;div class="col-md-3">
<app-shopping-cart (onOrderFinished)=finishOrder($event) #shoppingCartC [hidden]="orderFinished">
</vapp-shopping-cart>
</div>
<div class="col-md-6 offset-3">
<app-orders #ordersC [hidden]="!orderFinished"></app-orders>
</div>
</div>
<div *ngIf="showSearch">
<div class="card-deck" style="padding-bottom: 40px;">
<div class="col-lg-4 col-md-6 mb-4" *ngFor="let product of products let i = index;">
<div class="card text-center">
<div class="card-header" style="background-color: #bdc3c7;">
<h4>{{product.name}}</h4>
</div>
<div class="card-body">
<a (click)="sngleProduct(product.id)"><img class="card-img-top img-thumbnail"
style="width: 230px; height: 300px; cursor: pointer;" src={{product.pictureUrl}} alt="image"></a>
<h5 class="card-title" id="price">Price = {{product.price}}<i class="fas fa-dollar-sign"></i>
<button title="Information" id="btn" (click)=showUndoBtn(i) (click)="productInfo(product.id)">
<i class="fas fa-info-circle"></i></button>
<button title="View" id="btn" (click)="sngleProduct(product.id)"> <i class="fas fa-eye-slash"></i></button>
</h5>
<div class="modal" [attr.id]="'undoBtn'+i" *ngIf="showBtn===i && showMyContainerInfo" class="editBtn"
md-raised-button color="primary">
<div class="modal-content">
<span>{{product.description}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
We are going to create a dashboard page.
- dashboard.component.html
src/app/dashboard.component.ts
<app-ecommerce></app-ecommerce>
We are going to create a display-category page.
- display-category.component.ts
- display-category.component.html
src/app/display-category.component.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Product } from '../model/Model';
import { ProductService } from '../service/product.service';
@Component({
selector: 'app-display-category',
templateUrl: './display-category.component.html',
styleUrls: ['./display-category.component.css']
})
export class DisplayCategoryComponent implements OnInit {
products: Product[];
product: Product = {} as Product;
idCategory: number;
orderFinished = false;
showBtn = -1;
showMyContainerInfo = false;
constructor(private route: ActivatedRoute, private productService: ProductService,
private router: Router) {
this.route.params.subscribe(
params => {
this.idCategory = this.route.snapshot.params.idCategory;
this.productService.findProductsForCategory(this.idCategory).subscribe(products => {
this.products = products;
}
);
}
)
}
ngOnInit(): void { }
showUndoBtn(index) {
this.showBtn = index;
}
productInfo(id: number) {
this.productService.findProductById(id).subscribe(product => {
this.product = product;
});
this.showMyContainerInfo = !this.showMyContainerInfo;
}
sngleProduct(id: number) {
this.router.navigate(['sangle/product', id]);
}
}
src/app/display-category.component.html
<div class="container" [hidden]="orderFinished">
<div class="row">
<div class="col-lg-4">
<h2 class="title-page"><i class="fab fa-dropbox"></i> Products <i class="fab fa-dropbox"></i></h2>
</div>
</div>
</div>
<hr>
<div class="card-deck" style="padding-bottom: 40px;">
<div class="col-lg-4 col-md-6 mb-4" *ngFor="let product of products let i = index;">
<div class="card text-center">
<div class="card-header" style="background-color: #bdc3c7;">
<h4>{{product.name}}</h4>
</div>
<div class="card-body">
<a (click)="sngleProduct(product.id)"><img class="card-img-top img-thumbnail"
style="width: 230px; height: 300px; cursor: pointer;" src={{product.pictureUrl}} alt="image"></a>
<h5 class="card-title" id="price">Price = {{product.price}}<i class="fas fa-dollar-sign"></i>
<button title="Information" id="btn" (click)=showUndoBtn(i) (click)="productInfo(product.id)">
<i class="fas fa-info-circle"></i></button>
<button title="View" id="btn" (click)="sngleProduct(product.id)"> <i class="fas fa-eye-slash"></i></button>
</h5>
<div class="modal" [attr.id]="'undoBtn'+i" *ngIf="showBtn===i && showMyContainerInfo" class="editBtn"
md-raised-button color="primary">
<div class="modal-content">
<span>{{product.description}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
We are going to create a display-tag page.
- display-tag.component.ts
- display-tag.component.html
src/app/display-tag.component.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Product } from '../model/Model';
import { ProductService } from '../service/product.service';
import { TagService } from '../service/tag.service';
@Component({
selector: 'app-display-tag',
templateUrl: './display-tag.component.html',
styleUrls: ['./display-tag.component.css']
})
export class DisplayTagComponent implements OnInit {
products: Product[];
product: Product = {} as Product;
idTag: number;
orderFinished = false;
showBtn = -1;
showMyContainerInfo = false;
constructor(private route: ActivatedRoute, private productService: ProductService,
private router: Router, private tagService: TagService) {
this.route.params.subscribe(
params => {
this.idTag = this.route.snapshot.params.idTag;
this.tagService.findProductsForTag(this.idTag).subscribe(products => {
this.products = products;
}
);
}
)
}
ngOnInit(): void { }
showUndoBtn(index) {
this.showBtn = index;
}
productInfo(id: number) {
this.productService.findProductById(id).subscribe(product => {
this.product = product;
});
this.showMyContainerInfo = !this.showMyContainerInfo;
}
sngleProduct(id: number) {
this.router.navigate(['sangle/product', id]);
}
}
src/app/display-tag.component.html
<div class="container" [hidden]="orderFinished">
<div class="row">
<div class="col-lg-4">
<h2 class="title-page"><i class="fab fa-dropbox"></i> Products <i class="fab fa-dropbox"></i></h2>
</div>
</div>
</div>
<hr>
<div class="card-deck" style="padding-bottom: 40px;">
<div class="col-lg-4 col-md-6 mb-4" *ngFor="let product of products let i = index;">
<div class="card text-center">
<div class="card-header" style="background-color: #bdc3c7;">
<h4>{{product.name}}</h4>
</div>
<div class="card-body">
<a (click)="sngleProduct(product.id)"><img class="card-img-top img-thumbnail"
style="width: 230px; height: 300px; cursor: pointer;" src={{product.pictureUrl}} alt="image"></a>
<h5 class="card-title" id="price">Price = {{product.price}}<i class="fas fa-dollar-sign"></i>
<button title="Information" id="btn" (click)=showUndoBtn(i) (click)="productInfo(product.id)">
<i class="fas fa-info-circle"></i></button>
<button title="View" id="btn" (click)="sngleProduct(product.id)"> <i class="fas fa-eye-slash"></i></button>
</h5>
<div class="modal" [attr.id]="'undoBtn'+i" *ngIf="showBtn===i && showMyContainerInfo" class="editBtn"
md-raised-button color="primary">
<div class="modal-content">
<span>{{product.description}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
Add the AppRoutingModule
In Angular, the best practice is to load and configure the router in a separate, top-level module that is dedicated to routing and imported by the root AppModule.
By convention, the module class name is AppRoutingModule and it belongs in the app-routing.module.ts in the src/app folder.
app-routing-module.ts
src/app/app-routing.module.ts
import { ProfileComponent } from './profile/profile.component';
import { DashboardComponent} from './dashboard/dashboard.component';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
import { CategoriesComponent } from './admin/categories/categories.component';
import { SangleProductComponent } from './ecommerce/sangle-product/sangle-product.component';
import { DisplayCategoryComponent } from './display-category/display-category.component';
import { DisplayTagComponent } from './display-tag/display-tag.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{
path: 'dashboard',
component: DashboardComponent,
},
{
path: 'sangle/product/:idProduct',
component: SangleProductComponent
},
{
path: 'puy/product/:name',
component: SangleProductComponent
},
{
path: 'dsiplay-category/:idCategory',
component: DisplayCategoryComponent
},
{
path: 'display-tag/:idTag',
component: DisplayTagComponent
},
{
path: 'profile/:id',
component: ProfileComponent,
children: [
{
path: 'categories/:idCategory',
component: CategoriesComponent
}
]
}
];
@NgModule({
declarations: [],
imports: [CommonModule, RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
NgModules and JavaScript modules
The NgModule system is different from and unrelated to the JavaScript (ES2015) module system for managing collections of JavaScript objects. These are complementary module systems that you can use together to write your apps.
In JavaScript each file is a module and all objects defined in the file belong to that module. The module declares some objects to be public by marking them with the export key word. Other JavaScript modules use import statements to access public objects from other modules.
app-module.ts
src/app/app-module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { FormsModule } from '@angular/forms';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from './material-module';
import { ProfileComponent } from './profile/profile.component';
import { AppRoutingModule } from './app-routing.module';
import { DashboardComponent } from './dashboard/dashboard.component';
import { CategoriesComponent } from './admin/categories/categories.component';
import { AddCategoryComponent } from './admin/add-category/add-category.component';
import { AddProductComponent } from './admin/add-product/add-product.component';
import { AddTagComponent } from './admin/add-tag/add-tag.component';
import { AddTagToProductComponent } from './admin/add-tag-to-product/add-tag-to-product.component';
import { EcommerceComponent } from './ecommerce/ecommerce.component';
import { OrdersComponent } from './ecommerce/orders/orders.component';
import { ProductsComponent } from './ecommerce/products/products.component';
import { ShoppingCartComponent } from './ecommerce/shopping-cart/shopping-cart.component';
import { DatePipe } from '@angular/common';
import { SangleProductComponent } from './ecommerce/sangle-product/sangle-product.component';
import { UpdateProfileComponent } from './update-profile/update-profile.component';
import { DisplayCategoryComponent } from './display-category/display-category.component';
import { DisplayTagComponent } from './display-tag/display-tag.component';
@NgModule({
declarations: [
AppComponent,
LoginComponent,
ProfileComponent,
DashboardComponent,
CategoriesComponent,
AddCategoryComponent,
AddProductComponent,
AddTagComponent,
AddTagToProductComponent,
EcommerceComponent,
OrdersComponent,
ProductsComponent,
ShoppingCartComponent,
SangleProductComponent,
UpdateProfileComponent,
DisplayCategoryComponent,
DisplayTagComponent
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
NoopAnimationsModule,
MaterialModule,
AppRoutingModule
],
providers: [DatePipe],
bootstrap: [AppComponent],
schemas: [ CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA ]
})
export class AppModule { }
Conclusion
Now we have an overview of Angular 10 + Spring Boot App.
We also take a look at client-server architecture for REST API using Spring Web MVC & Spring Data JPA, as well as Angular 10 project structure for building a front-end app to make HTTP requests and consume responses.