Getting Started | Building an Application with Ionic
In this part 2 of shopping project application we will buid an application with Ionic framewotk
In this project we want to build an application shopping with spring boot and ionic. the project content Objects User, Shopping, Category, Product and Cart the Admin can add all information after login and the user can choose a product to add in his cart also he can save the product to his profile.
Ionic apps are created and developed primarily through the Ionic command line utility (the “CLI”), and use Cordova to build/deploy as a native app. This means we need to install a few utilities to get developing.
Installing Ionic
Ionic apps are created and developed primarily through the Ionic command-line utility. The Ionic CLI is the preferred method of installation, as it offers a wide range of dev tools and help options along the way. It is also the main tool through which to run the app and connect it to other services, such as Ionic Appflow.
Before proceeding, make sure your computer has Node.js installed.
Install the Ionic CLI with npm:
$ npm install -g @ionic/cli
Starting an App
Starting a new Ionic app is incredibly simple. From the command line, run the ionic start command and the CLI will handle the rest.
Here, myApp is the name of the project, blank is the starter template, and the project type is angular.
$ ionic start shopping-app
Project structure
Let's go through the files and folders of the app.
/ src
Inside of the /src directory we find our raw, uncompiled code. This is where most of the work for your Ionic app will take place.
/ app
The App folder is the largest folder because it contains all the code of our ionic app. It has all the components, modules, pages, services and styles you will use to build your app.
This is the core of the project. Let’s have a look at the structure of this folder so you get an idea where to find things and where to add your own modules to adapt this project to your particular needs.
Models
Create a folder modal in side it add a class Model.ts
src/app/modal/Modal.ts
export class Cart {
id: number;
name: string;
count: number;
total: number;
price: number;
added: any;
}
export class Category {
id: number;
name: string;
logo: string;
expanded: boolean;
products: Product[];
}
export class Product {
id: number;
name: string;
description: string;
price: number;
image: string;
created: any;
}
export class Shopping {
id: number;
name: string;
expanded: boolean;
categories: Category[];
}
export class User {
id: any;
username: string;
password: string;
admin: boolean;
carts: Cart[];
shoppings: Shopping[];
}
Angular Services
Angular services are singleton objects that get instantiated only once during the lifetime of an application. They contain methods that maintain data throughout the life of an application, i.e. data does not get refreshed and is available all the time. The main objective of a service is to organize and share business logic, models, or data and functions with different components of an Angular application.
An example of when to use services would be to transfer data from one controller to another custom service.
Why Should We Use Services in Angular? The separation of concerns is the main reason why Angular services came into existence. An Angular service is a stateless object and provides some very useful functions. These functions can be invoked from any component of Angular, like Controllers, Directives, etc. This helps in dividing the web application into small, different logical units which can be reused.
Create two services in the service package
- ShoppingService- UserService
src/app/service/shopping.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Cart, Category, Product, Shopping } from '../modal/Modal';
@Injectable({
providedIn: 'root'
})
export class ShoppingService {
private url = 'http://localhost:8080/api';
constructor(private http: HttpClient) { }
addShoppingToUser(shopping: Shopping, idUser: number): Observable<Shopping> {
return this.http.post<Shopping>(`${this.url}/addShoppingToUser/${idUser}`, shopping);
}
addCategoryToShopping(category: Category, idShopping: number): Observable<Category> {
return this.http.post<Category>(`${this.url}/addCategoryToShopping/${idShopping}`, category);
}
addCartToUser(cart: Cart, idUser: number): Observable<Cart> {
return this.http.post<Cart>(`${this.url}/addCartToUser/${idUser}`, cart);
}
addProductToCart(product: Product, idCart: number): Observable<Product> {
return this.http.post<Product>(`${this.url}/addProductToCart/${idCart}`, product);
}
addProductToCategory(product: Product, idCategory: number): Observable<Product> {
return this.http.post<Product>(`${this.url}/addProductToCategory/${idCategory}`, product);
}
findCategoriesToShopping(idShopping: number): Observable<Category[]> {
return this.http.get<Category[]>(`${this.url}/findCategoriesToShopping/${idShopping}`);
}
findCategories(): Observable<Category[]> {
return this.http.get<Category[]>(`${this.url}/findCategories`);
}
findProductsToCategory(idProduct: number): Observablee<Product[]> {
return this.http.get<Product[]>(`${this.url}/findProductsToCategory/${idProduct}`);
}
findProducts(): Observable<Product[]> {
return this.http.get<Product[]>(`${this.url}/findProducts`);
}
private cart = [];
getCart() {
return this.cart;
}
addProduct(product: any) {
this.cart.push(product);
}
}
src/app/service/user.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Cart, Category, Shopping, User } from '../modal/Modal';
const USERNAME_KEY = 'AuthUsername';
@Injectable({
providedIn: 'root'
})
export class UserService {
private url = 'http://localhost:8080/api';
constructor(private http: HttpClient) { }
addUser(user: User): Observable<User> {
return this.http.post<User>(`${this.url}/addUser`, user);
}
editUser(user: User, idUser: number): Observable<User> {
return this.http.put<User>(`${this.url}/editUser/${idUser}`, user);
}
deleteUser(idUser: number): Observable<User> {
return this.http.delete<User>(`${this.url}/deleteUser/${idUser}`);
}
findCartsToUser(idUser: number): Observable<Cart[]> {
return this.http.get<Cart[]>(`${this.url}/findCartsToUser/${idUser}`);
}
findShoppingToUser(idUser: number): Observable<Shopping[]> {
return this.http.get<Shopping[]>(`${this.url}/findShoppingToUser/${idUser}`);
}
findUserById(idUser: number): Observable<User> {
return this.http.get<User>(`${this.url}/findUserById/${idUser}`);
}
findUserByUsername(username: string): Observable<User> {
return this.http.get<User>(`${this.url}/findUserByUsername/${username}`);
}
public saveUsername(username: string) {
window.sessionStorage.removeItem(USERNAME_KEY);
window.sessionStorage.setItem(USERNAME_KEY, username);
}
public getUsername(): string {
return sessionStorage.getItem(USERNAME_KEY);
}
public signOut() {
window.sessionStorage.clear();
}
}
Login page
Now we'll continue with the project by adding pages which are the basic buildings of an Ionic app. So let's get started. You can create pages either manually or generating them using the Ionic CLI v5 which is the recommended method. In this guide we'll look first at how to create a page generate it with the Ionic CLI, then how to add it to the project.
- add-category- add-product
- add-shopping
- cart
- dashboard
- home
- login
- profile
Go ahead and open your terminal or command prompt and follow the instructions:
$ ng generate page login
We will use these components
- login.page.ts- login.page.html
src/app/login.page.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { User } from '../modal/Model';
import { UserService } from '../service/user.service';
@Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss']
})
export class LoginPage implements OnInit {
progressBar = false;
user: User = {} as User;
username: string;
constructor(private userService: UserService, private router: Router) { }
ngOnInit() {
this.username = this.userService.getUsername();
if(this.username!=null) {
this.userService.findUserByUsername(this.username).subscribe(user => {
this.user = user;
this.username = user.username;
});
}
}
onSubmit() {
this.userService.findUserByUsername(this.user.username).subscribe(user => {
if(this.user.username=='admin' && this.user.password == 'admin'
|| this.user.username=='drmas' && this.user.password == 'drmas') {
if(this.user!=null) {
this.user.admin = true;
this.userService.addUser(this.user).subscribe(addUser => {
this.user = addUser;
this.router.navigate(['/dashboard/', this.user.username]);
this.userService.saveUsername(this.user.username);
});
}
} else {
if(this.user!=null) {
this.user.admin = false;
this.userService.addUser(this.user).subscribe(addUser => {
this.user = addUser;
this.userService.saveUsername(this.user.username);
this.router.navigate(['/home/', this.user.username]);
});
}
}
});
}
}
src/app/login.page.html
<ion-header>
<ion-toolbar>
<ion-title>Welcome to shopping</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div style="font-size: 100px; text-align: center;">
<ion-icon name="person-circle-outline"></ion-icon>
</div>
<ion-card>
<ion-spinner name="bubbles" color="primary" class="center" *ngIf="progressBar"></ion-spinner>
<ion-card-header color="danger">
<ion-card-title>Authentication </ion-card-title>
</ion-card-header>
<ion-card-content>
<form name="user" (ngSubmit)="onSubmit()" #formRegister="ngForm" novalidate>
<ion-item>
<ion-input type="text" id="username" placeholder="Enter username" name="username" [(ngModel)]="user.username"
#username="ngModel" required></ion-input>
</ion-item>
<ion-item>
<ion-input type="password" id="password" placeholder="Enter password" name="password"
[(ngModel)]="user.password" #password="ngModel" required></ion-input>
</ion-item>
<br>
<ion-button type="submit" color="primary" fill="solid" size="large" expand="block"
[disabled]="username.invalid || password.invalid">Login</ion-button>
</form>
</ion-card-content>
</ion-card>
</ion-content>
Admin dashboard
In this components we ere going create addShopping, addCategory, addProduct and display all shoppings and categodries, we will use ModalController
ModalController
A Modal is a content pane that goes over the user's current page. Usually it is used for making a choice or editing an item. A modal uses the NavController to present itself in the root nav stack.
Go ahead and open your terminal or command prompt and follow the instructions:
$ ng generate page dashboard
We will use these components
- dashboard.page.ts- dashboard.page.html
- dashboard.page.scss
src/app/dashboard.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { User, Category } from '../modal/Model';
import { UserService } from '../service/user.service';
import { ModalController } from '@ionic/angular';
import { AddCategoryPage } from '../add-category/add-category.page';
import { AddProductPage } from '../add-product/add-product.page';
import { AddShoppingPage } from '../add-shopping/add-shopping.page';
import { ShoppingService } from '../service/shopping.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.page.html',
styleUrls: ['./dashboard.page.scss']
})
export class DashboardPage implements OnInit {
shoppings: any[];
categories: any[];
user: User = {} as User;
username: string;
categoryLength: number;
showIndex =- 1;
sliderConfig = {
spaceBetween: 20,
centeredSlides: true,
slidesPerView: 1.6
};
constructor(private route: ActivatedRoute, public modalController: ModalController,
private userService: UserService, private shoppingService: ShoppingService, private router: Router) { }
ngOnInit() {
this.username = this.route.snapshot.params.username;
this.userService.findUserByUsername(this.username).subscribe(user => {
this.user = user;
this.userService.findShoppingToUser(this.user.id).subscribe(shoppings => {
this.shoppings = shoppings;
})
});
}
toggle(item: any, id: number, index: any) {
item.expanded = !item.expanded;
this.showIndex = index;
this.shoppingService.findCategoriesToShopping(id).subscribe(categories => {
this.categories = categories;
this.categoryLength = this.categories.length;
});
}
async addShopping(idUser: number) {
const modal = await this.modalController.create({
component: AddShoppingPage,
swipeToClose: true,
componentProps: {idUser}
});
return await modal.present();
}
async addCategory(idShopping: number) {
const modal = await this.modalController.create({
component: AddCategoryPage,
swipeToClose: true,
componentProps: {idShopping}
});
return await modal.present();
}
async addProduct(idCategory: number) {
const modal = await this.modalController.create({
component: AddProductPage,
swipeToClose: true,
componentProps: {idCategory}
});
return await modal.present();
}
logout() {
this.userService.signOut();
this.router.navigateByUrl("/login")
}
}
src/app/dashboard.html
<ion-content style="padding: 0 16px" [fullscreen]="true">
<div class="header">
<h2>Welcome {{username}}</h2>
</div>
<div class="flex">
<div class="border-blue">
<div class="border-white">
<div class="img-box">
<img style="height: 220px"
src="https://img.over-blog-kiwi.com/0/87/20/59/20190804/ob_f940bb_8bf3477e-e55c-4f56-ab33-59d3380f899e.jpeg" />
</div>
</div>
</div>
</div>
<div style="padding: 0% 16px">
<ion-button color="success" expand="block" fill="outline" (click)="addShopping(user.id)">Add shopping</ion-button>
</div>
<br />
<div *ngFor="let item of shoppings; let i = index" class="category-block">
<ion-row no-padding class="category-banner" style="background-color: #d5d5d7">
<ion-col size="10" text-left button (click)="toggle(item, item.id, i)" align-self-center>
<label tappable>{{item.name}}</label>
</ion-col>
<ion-col size="2" (click)="addCategory(item.id)">
<ion-icon color="danger" name="add-outline" style="font-size: 28px; cursor: pointer; margin-top: -6px">
</ion-icon>
</ion-col>
</ion-row>
<ion-slides [options]="sliderConfigs">
<ion-slide *ngFor="let cat of categories; let ii = index">
<div *ngIf="showIndex ===i && item.expanded" [attr.id]="'undoBtn'+i">
<ion-card>
<ion-card-header>
<ion-card-title> {{ii+1}} {{cat.name}} </ion-card-title>
<ion-card-content>
<img src="{{cat.logo}}" alt="img" />
<ion-button expand="full" color="danger" style="margin-top: 10px" shape="round"
(click)="addProduct(cat.id)">Add product information</ion-button>
</ion-card-content>
</ion-card-header>
</ion-card>
</div>
</ion-slide>
</ion-slides>
</div>
<p *ngIf="categoryLength == 0" id="emptyMessage">Sorry, nothing in here</p>
</ion-content>
<ion-footer class="ion-no-border">
<ion-toolbar color="danger">
<ion-title (click)="logout(user.id)" style="cursor: pointer">
Logout
</ion-title>
</ion-toolbar>
</ion-footer>
src/app/dashboard.scss
.header {
background: #1abc9c;
height: 140px;
padding-top: 1px;
}
.header h2 {
color: #ffffff;
font-weight: bold;
text-align: center;
}
.header .space-between {
display: flex;
justify-content: space-between;
padding: 10px 10px 0 10px;
}
.header .followings {
display: flex;
flex-direction: column;
align-items: center;
}
.header .followings p {
color: #ffffff;
margin: 8px 0 0 0;
}
.img-box {
height: 130px;
width: 130px;
border-radius: 50%;
overflow: hidden;
}
.border-white {
border: 4px solid #ffffff;
border-radius: 50%;
width: fit-content;
}
.border-blue {
border: 7px solid #16a085;
border-radius: 50%;
width: fit-content;
}
.flex {
display: flex;
justify-content: center;
margin-top: -76px;
}
ion-content {
--background: var(--ion-color-light);
}
.accordoin-list {
margin-bottom: 4px;
--ion-item-background: #ffffff;
.section,
.section-active {
--min-height: 58px;
}
}
.section {
--ion-item-background: #ffffff;
--ion-item-color: #000000;
}
.section-active {
--ion-item-background: #ffc400;
--ion-item-color: #ffffff;
font-weight: 600;
ion-icon {
color: #ffffff;
}
}
.child-list {
padding: 0px;
margin: 0px;
.child,
.child-active {
margin-bottom: 2px;
}
}
.child {
--ion-item-background: #e8e7e6;
--ion-item-color: #000000;
}
.child-active {
--ion-item-background: #fad86b;
--ion-item-color: #ffffff;
ion-icon {
color: #ffffff;
}
}
.padding-list {
padding: 0px;
margin: 0px;
}
.category-block {
margin-bottom: 4px;
}
.category-banner {
border-left: 10px solid #1abc9c;
background: var(--ion-color-light);
height: 40px;
padding: 10px;
font-weight: 500;
}
#emptyMessage {
color: #c80c0c;
background: antiquewhite;
padding: 10px 25px;
font-weight: bold;
}
Add shopping
In this components we ere going create add shopping ModalController
- add-shopping.page.ts- add-shopping.page.html
src/app/add-shopping.ts
import { Component, OnInit } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { Shopping } from '../modal/Model';
import { ShoppingService } from '../service/shopping.service';
@Component({
selector: 'app-add-shopping',
templateUrl: './add-shopping.page.html',
styleUrls: ['./add-shopping.page.scss']
})
export class AddShoppingPage implements OnInit {
idUser: number;
shopping: Shopping = {} as Shopping;
progessBar = false;
constructor(private modalController: ModalController, private shoppingService: ShoppingService) { }
ngOnInit(): void { }
addShopping() {
this.progessBar = true;
this.shoppingService.addShoppingToUser(this.shopping, this.idUser).subscribe(shopping => {
this.shopping = shopping;
window.location.reload();
});
}
cancel() {
this.modalController.dismiss();
}
}
src/app/add-shopping.html
<ion-header>
<ion-toolbar color="danger">
<ion-buttons slot="secondary">
<ion-button fill="outline" (click)="cancel()">
<ion-icon slot="start" name="close-outline"></ion-icon>
Cancel
</ion-button>
</ion-buttons>
<ion-title>add shopping name</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-spinner name="bubbles" color="primary" class="center" *ngIf="progressBar"></ion-spinner>
<ion-card>
<ion-card-content>
<form name="shopping" (ngSubmit)="addShopping()" #formRegister="ngForm" novalidate>
<ion-item>
<ion-input type="text" placeholder="Enter shopping name" name="name" [(ngModel)]="shopping.name"
#name="ngModel" required></ion-input>
</ion-item>
<br>
<ion-button type="submit" color="primary" fill="solid" size="large" expand="block" [disabled]="name.invalid">
Save
</ion-button>
</form>
</ion-card-content>
</ion-card>
</ion-content>
Add category
In this components we ere going create add category ModalController
- add-category.page.ts- add-category.page.html
src/app/add-category.ts
import { Component, OnInit } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { Shopping } from '../modal/Model';
import { ShoppingService } from '../service/shopping.service';
@Component({
selector: 'app-add-category',
templateUrl: './add-category.page.html',
styleUrls: ['./add-category.page.scss']
})
export class AddCategoryPage implements OnInit {
idShopping: number;
category: Category = {} as Category;
progessBar = false;
constructor(private modalController: ModalController, private shoppingService: ShoppingService) { }
ngOnInit(): void { }
addCategory() {
this.progessBar = true;
this.shoppingService.addCategoryToShopping(this.category, this.idShopping).subscribe(category => {
this.category = category;
window.location.reload();
});
}
cancel() {
this.modalController.dismiss();
}
}
src/app/add-category.html
<ion-header>
<ion-toolbar color="primary">
<ion-buttons slot="secondary">
<ion-button fill="outline" (click)="cancel()">
<ion-icon slot="start" name="close-outline"></ion-icon>
Cancel
</ion-button>
</ion-buttons>
<ion-title>add category name</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-spinner name="bubbles" color="primary" class="center" *ngIf="progressBar"></ion-spinner>
<ion-card>
<ion-card-content>
<form name="shopping" (ngSubmit)="addSCategory()" #formRegister="ngForm" novalidate>
<ion-item>
<ion-input type="text" placeholder="Enter category name" name="name" [(ngModel)]="category.name"
#name="ngModel" required></ion-input>
</ion-item><br>
<ion-item>
<ion-input type="text" placeholder="Enter category logo" name="logo" [(ngModel)]="category.logo"
#logo="ngModel" required></ion-input>
</ion-item><br>
<ion-button type="submit" color="primary" fill="solid" size="large" expand="block" [disabled]="name.invalid || logo.invalid">
Save</ion-button>
</form>
</ion-card-content>
</ion-card>
</ion-content>
Add product
In this components we ere going create add product ModalController
- add-product.page.ts- add-product.page.html
src/app/add-product.ts
import { Component, OnInit } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { Shopping } from '../modal/Model';
import { ShoppingService } from '../service/shopping.service';
@Component({
selector: 'app-add-product',
templateUrl: './add-product.page.html',
styleUrls: ['./add-product.page.scss']
})
export class AddProductPage implements OnInit {
idCategory: number;
product: Product = {} as Product;
progessBar = false;
constructor(private modalController: ModalController, private shoppingService: ShoppingService) { }
ngOnInit(): void { }
addProduct() {
this.progessBar = true;
this.shoppingService.addProductToCategory(this.product, this.idCategory).subscribe(product => {
this.product = product;
window.location.reload();
});
}
cancel() {
this.modalController.dismiss();
}
}
src/app/add-product.html
<ion-header>
<ion-toolbar color="warning">
<ion-buttons slot="secondary">
<ion-button fill="outline" (click)="cancel()">
<ion-icon slot="start" name="close-outline"></ion-icon>
Cancel
</ion-button>
</ion-buttons>
<ion-title>add product name</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-spinner name="bubbles" color="primary" class="center" *ngIf="progressBar"></ion-spinner>
<ion-card>
<ion-card-content>
<form name="shopping" (ngSubmit)="addProduct()" #formRegister="ngForm" novalidate>
<ion-item>
<ion-input type="text" placeholder="Enter product name" name="name" [(ngModel)]="category.name"
#name="ngModel" required></ion-input>
</ion-item><br>
<ion-item>
<ion-input type="text" placeholder="Enter product description" name="description" [(ngModel)]="product.description"
#description="ngModel" required></ion-input>
</ion-item><br>
<ion-item>
<ion-input type="number" placeholder="Enter product price" name="price" [(ngModel)]="product.price"
#price="ngModel" required></ion-input>
</ion-item><br>
<ion-item>
<ion-input type="text" placeholder="Enter product image" name="image" [(ngModel)]="product.image"
#image="ngModel" required></ion-input>
</ion-item><br>
<ion-button type="submit" color="primary" fill="solid" size="large" expand="block" [disabled]="name.invalid || price.invalid || description.invalid || image.invalid">
Save</ion-button>
</form>
</ion-card-content>
</ion-card>
</ion-content>
Home page
In this components we ere going display all products
- add-home.page.ts- add-home.page.html
- add-home.page.scss
src/app/home.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { User } from '../modal/Model';
import { StorageService } from '../service/storage.service';
import { UserService} from '../service/user.service';
import { ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: './home.page.html',
styleUrls: ['./home.page.scss']
})
export class HomePage implements OnInit {
products: any[] = [];
categories: any[] = [];
cart: any[] = [];
user: User = {} as User;
username: string;
productLength: number;
showIndex =- 1;
constructor(private userService: UserService, private shoppingService: ShoppingService, private router: Router,
private route: ActivatedRoute) {}
ngOnInit(): void {
this.cart = this.shoppingService.getCart();
this.username = this.route.snapshot.params.username;
this.userService.findUserByUsername(this.username).subscribe(user => {
this.user = user;
});
this.shoppingService.findCategories().subscribe(categories => {
this.categories = categories;
});
}
toggle(item: any, id: number, index: any) {
item.expanded = !item.expanded;
this.showIndex = index;
this.shoppingService.findProductsToCategory(id).subscribe(products => {
this.products = products
this.productLength = this.products.length;
});
}
addToCart(product: any) {
this.shoppingService.addProduct(product);
}
openCart(idUser: number) {
this.router.navigate(['/cart/', idUser]);
}
logout(id: number) {
this.userService.deleteUser(id).subscribe(() => {
this.userService.signOut();
this.router.navigateByUrl("/login")
});
}
}
src/app/home.html
<ion-header>
<ion-toolbar color="secondary">
<ion-title>
Welcome {{user.username}} to shopping
</ion-title>
<ion-buttons slot="end" (click)="openCart(user.id)">
<ion-badge *ngIf="cart.length > 0" color="danger"> {{cart.length}} </ion-badge>
<ion-button>
<ion-icon name="cart" slot="icon-only" color="medium"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<div *ngFor="let item of categories; let i = index" class="category-block">
<ion-row no-padding class="category-banner" style="background-color: #d5d5d7;">
<ion-col text-left button (click)="toggle(item, item.id, i)" align-self-center>
<label tappable>{{item.name}}</label>
</ion-col>
</ion-row>
<ion-slides [options]="sliderConfigs">
<ion-slide *ngFor="let pro of products; let ii = index">
<div *ngIf="showIndex ===i && item.expanded" [attr.id]="'undoBtn'+i">
<ion-card>
<ion-card-header>
<ion-card-title>
{{ii+1}} {{pro.name}}
</ion-card-title>
<ion-card-content>
<img src="{{pro.image}}" alt="img">
<ion-button expand="full" color="danger" style="margin-top: 10px;" shape="round"
(click)="addToCart(pro)">Add to cart </ion-button>
</ion-card-content>
</ion-card-header>
</ion-card>
</div>
</ion-slide>
</ion-slides>
</div>
<p *ngIf="productLength == 0" id="emptyMessage">Sorry, nothing in here</p>
</ion-content>
<ion-footer class="ion-no-border">
<ion-toolbar color="danger">
<ion-title (click)="logout(user.id)" style="cursor: pointer;"> logout </ion-title>
</ion-toolbar>
</ion-footer>
src/app/shopping/home.scss
ion-badge {
color: #fff;
position: absolute;
top: 0;
right: 0;
border-radius: 100%;
cursor: pointer;
z-index: 3;
}
.category-block {
margin-bottom: 4px;
margin-top: 15px;
}
.category-banner {
border-left: 8px solid var(--ion-color-secondary);
background: var(--ion-color-light);
height: 40px;
padding: 10px;
font-weight: 500;
}
Cart page
In this components we ere going to display chossen products
- add-cart.page.ts- add-cart.page.html
src/app/cart.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { User, Cart } from '../modal/Model';
import { StorageService } from '../service/storage.service';
import { UserService} from '../service/user.service';
@Component({
selector: 'app-cart',
templateUrl: './cart.page.html',
styleUrls: ['./cart.page.scss']
})
export class CartPage implements OnInit {
selectedItems: Cart[];
user: User = {} as User;
cart: Cart = {} as Cart;
total = 0;
idUser: number;
product: {};
constructor(private shoppingService: ShoppingService, private router: Router,
private route: ActivatedRoute, private userService: UserService) { }
ngOnInit() {
this.idUser = this.route.snapshot.params.idUser;
this.userService.findUserById(this.idUser).subscribe(user => {
this.user = user;
});
const categories = this.shoppingService.getCart();
const selected = {};
for (const obj of categories) {
if (selected[obj.id]) {
selected[obj.id].count++;
} else {
selected[obj.id] = { ...obj, count: 1 };
}
}
this.selectedItems = Object.keys(selected).map(key => selected[key]);
this.total = this.selectedItems.reduce((a, b) => a + (b.count * b.price), 0);
}
saveCart(total: number, item: any) {
this.cart.total = total;
this.selectedItems.forEach(product => {
this.cart.name = product.name;
this.cart.price = product.price;
this.cart.count = product.count
this.shoppingService.addCartToUser(this.cart, this.idUser).subscribe(cart => {
this.cart = cart;
this.router.navigate(["/profile/", this.idUser]);
});
})
}
home(username: string) {
this.router.navigate(["/home/", username]);
}
}
src/app/cart.html
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>My cart {{user.username}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of selectedItems" lines="inset">
<ion-label>{{item.count}}: {{item.name}} - {{item.price | currency:'USD':'symbol'}}</ion-label>
<ion-note slot="end" color="tertiary">{{ (item.price * item.count) | currency:'USD':'symbol' }}</ion-note>
</ion-item>
<ion-item color="success">
Total: <span slot="end">{{total | currency:'USD':'symbol'}</span>
</ion-item>
</ion-list><br>
<ion-button shape="full" color="danger" (click)="saveCart(total, product)">Save</ion-button>
</ion-content>
Profile page
In this components we ere going to display chossen products
- add-cart.profile.ts- add-cart.profile.html - add-cart.profile.scss
src/app/.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { User, Cart } from '../modal/Model';
import { UserService } from '../service/user.service';
@Component({
selector: 'app-profile',
templateUrl: './profile.page.html',
styleUrls: ['./profile.page.scss']
})
export class ProfilePage implements OnInit {
carts: Cart[];
user: User = {} as User;
idUser: number;
total: number;
constructor(private userService: UserService, private route: ActivatedRoute,
private router: Router) { }
ngOnInit() {
this.idUser = this.route.snapshot.params.idUser;
this.userService.findCartsToUser(this.idUser).subscribe(carts => {
this.carts = carts;
this.total = this.carts.reduce((a, b) => a + (b.count * b.price), 0);
});
this.userService.findUserById(this.idUser).subscribe(user => {
this.user = user;
});
}
logout(id: number) {
this.userService.deleteUser(id).subscribe(() => {
this.userService.signOut();
this.router.navigateByUrl("/login")
});
}
}
src/app/profile.html
<ion-content>
<div class="header">
<h2>Wlecome {{user.username}}</h2>
<div class="space-between">
<div class="followings">
<ion-badge color="danger" mode="ios">42</ion-badge>
<p>Abonnés</p>
</div>
<div class="followings">
<ion-badge color="danger" mode="ios">142</ion-badge>
<p>Abonnements</p>
</div>
</div>
</div>
<div class="flex">
<div class="border-blue">
<div class="border-white">
<div class="img-box">
<img
src="https://img.over-blog-kiwi.com/0/87/20/59/20190804/ob_f940bb_8bf3477e-e55c-4f56-ab33-59d3380f899e.jpeg"
alt="">
</div>
</div>
</div>
</div>
<ion-card>
<ion-item lines="none">
<ion-avatar slot="start">
<img
src="https://img.over-blog-kiwi.com/0/87/20/59/20190804/ob_f940bb_8bf3477e-e55c-4f56-ab33-59d3380f899e.jpeg" />
</ion-avatar>
<ion-label> <b>
<h2>{{user.username}}</h2>
</b>
<p>Il y a 23 min</p>
</ion-label>
</ion-item> <br>
<ion-list>
<ion-item lines="none" class="tweet">
<ion-label class="ion-text-wrap">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore officiis voluptates eos sit eveniet commodi
laborum accusamus porro, beatae non adipisci. Enim explicabo facere harum labore delectus provident ad minus.
</ion-label>
</ion-item>
<ion-item *ngFor="let item of carts" lines="inset">
<ion-label>{{item.count}}: {{item.name}} - {{item.added | date}}</ion-label>
<ion-note slot="end" color="tertiary">{{ (item.price * item.count) | currency:'USD':'symbol' }}</ion-note>
</ion-item>
<ion-item color="success">
Total: <span slot="end">{{total | currency:'USD':'symbol'}} </span>
</ion-item>
</ion-list><br>
</ion-card>
</ion-content>
<ion-footer class="ion-no-border">
<ion-toolbar color="danger">
<ion-title (click)="logout(user.id)" style="cursor: pointer;"> Logout </ion-title>
</ion-toolbar>
</ion-footer>
src/app/profile.scss
.header {
background: #e74c3c;
height: 180px;
padding-top: 1px;
}
.header h2 {
color: #ffffff;
font-weight: bold;
text-align: center;
}
.header .space-between {
display: flex;
justify-content: space-between;
padding: 10px 10px 0 10px;
}
.header .followings {
display: flex;
flex-direction: column;
align-items: center;
}
.header .followings p {
color: #ffffff;
margin: 8px 0 0 0;
}
.img-box {
height: 130px;
width: 130px;
border-radius: 50%;
overflow: hidden;
}
.border-white {
border: 4px solid #ffffff;
border-radius: 50%;
width: fit-content;
}
.border-blue {
border: 7px solid #c0392b;
border-radius: 50%;
width: fit-content;
}
.flex {
display: flex;
justify-content: center;
margin-top: -76px;
}
.tweet {
margin-top: -10px;
}
.tweet ion-label {
line-height: 1 !important;
font-size: 15px;
margin: 6px 0 !important;
min-height: 34px;
}
.tweet-img {
width: 95%;
margin-left: 2.5%;
border-radius: 10px;
}
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 { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{
path: '',
redirectTo: 'login',
pathMatch: 'full'
},
{
path: 'login',
loadChildren: () => import('./login/login.module').then(m => m.LoginPageModule)
},
{
path: 'dashboard/:username',
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardPageModule)
},
{
path: 'home/:username',
loadChildren: () => import('./home/home.module').then(m => m.HomePageModule)
},
{
path: 'add-category',
loadChildren: () => import('./add-category/add-category.module').then(m => m.AddCategoryPageModule)
},
{
path: 'add-product',
loadChildren: () => import('./add-product/add-product.module').then(m => m.AddProductPageModule)
},
{
path: 'add-shopping',
loadChildren: () => import('./add-shopping/add-shopping.module').then(m => m.AddShoppingPageModule)
},
{
path: 'cart/:idUser',
loadChildren: () => import('./cart/cart.module').then(m => m.CartPageModule)
},
{
path: 'profile/:idUser',
loadChildren: () => import('./profile/profile.module').then(m => m.ProfilePageModule)
},
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
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 { CUSTOM_ELEMENTS_SCHEMA, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
FormsModule,
HttpClientModule,
],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
NO_ERRORS_SCHEMA
],
bootstrap: [AppComponent]
})
export class AppModule { }
Conclusion
Now we have an overview of Spring Boot CRUD example when building a CRUD App.
We also take a look at client-server architecture for REST API using Spring Web MVC & Spring Data JPA, as well, we ware creating an Ionic app with Angular 10 project structure for building a front-end app to make HTTP requests and consume responses.