Ionic 4, Angular 7 and Cordova Tutorial: Build CRUD Mobile Apps
Ionic 4, Angular 7 and Cordova Tutorial: Build CRUD Mobile Apps
Ionic 4, Angular 7 and Cordova Tutorial: Build CRUD Mobile Apps
The following tools, frameworks, and modules are required for this tutorial:
Node.js (Recommended version)
Ionic 4 beta
Angular 7
Express and MongoDB API
Terminal or Node command line
IDE or Text Editor
Before going to the main steps, we assume that you have to install Node.js. Next, upgrade or install new Ionic 4
CLI by open the terminal or Node command line then type this command.
sudo npm install -g ionic
You will get the latest Ionic CLI in your terminal or command line. Check the version by type this command.
ionic --version
4.3.1
1
"@ionic-native/splash-screen": "5.0.0-beta.21",
"@ionic-native/status-bar": "5.0.0-beta.21",
"@ionic/angular": "4.0.0-beta.15",
"core-js": "^2.5.3",
"rxjs": "6.2.2",
"zone.js": "^0.8.26"
},
Next, we have to upgrade the angular version to 7. You can replace all dependencies in `package.json` with this.
"dependencies": {
"@angular/common": "^7.0.3",
"@angular/core": "^7.0.3",
"@angular/forms": "^7.0.3",
"@angular/http": "^7.0.3",
"@angular/platform-browser": "^7.0.3",
"@angular/platform-browser-dynamic": "^7.0.3",
"@angular/router": "^7.0.3",
"@ionic-native/core": "5.0.0-beta.21",
"@ionic-native/splash-screen": "5.0.0-beta.21",
"@ionic-native/status-bar": "5.0.0-beta.21",
"@ionic/angular": "4.0.0-beta.15",
"core-js": "^2.5.3",
"rxjs": "6.2.2",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@angular-devkit/architect": "^0.10.4",
"@angular-devkit/build-angular": "^0.10.4",
"@angular-devkit/core": "^7.0.4",
"@angular-devkit/schematics": "^7.0.4",
"@angular/cli": "^7.0.4",
"@angular/compiler": "^7.0.3",
"@angular/compiler-cli": "^7.0.3",
"@angular/language-service": "^7.0.3",
"@ionic/angular-toolkit": "^1.0.0",
"@ionic/lab": "^1.0.13",
"@types/jasmine": "^2.8.11",
"@types/jasminewd2": "^2.0.6",
"@types/node": "^10.12.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.0",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "^3.1.6"
},
2
Then run this commands.
rm -rf node_modules
npm install
As usual, run the Ionic 4 and Angular 7 app for the first time, but before run as `lab` mode, type this command to
install `@ionic/lab`.
npm install --save-dev @ionic/lab
ionic serve -l
Now, open the browser and you will the Ionic 4 and Angular 7 app with the iOS, Android, or Windows view. If
you see a normal Ionic 4 tabs application, that's mean the Angular upgrade process is successful.
3
MatCardModule,
MatFormFieldModule } from "@angular/material";
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ScrollingModule } from '@angular/cdk/scrolling';
Register the above modules to `@NgModule` imports.
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
BrowserAnimationsModule,
DragDropModule,
ScrollingModule,
MatInputModule,
MatPaginatorModule,
MatProgressSpinnerModule,
MatSortModule,
MatTableModule,
MatIconModule,
MatButtonModule,
MatCardModule,
MatFormFieldModule
],
4
import { Observable, of, throwError } from 'rxjs';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
import { Product } from './product';
these constants before the `@Injectable`.
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
const apiUrl = "/api/v1/products";
Inject `HttpClient` module to the constructor.
constructor(private http: HttpClient) { }
Add the error handler function.
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
6
{
path: '',
redirectTo: '/tabs/(home:home)',
pathMatch: 'full'
}
];
Next, open and edit `src/app/tabs/tabs.module.ts` then add or replace this imports.
import { AddPageModule } from '../add/add.module';
import { EditPageModule } from '../edit/edit.module';
import { HomePageModule } from '../home/home.module';
import { DetailsPageModule } from '../details/details.module';
Add those imported modules to the `@NgModule` imports array.
imports: [
IonicModule,
CommonModule,
FormsModule,
TabsPageRoutingModule,
HomePageModule,
AddPageModule,
EditPageModule,
DetailsPageModule
],
Next, open and edit `src/app/tabs/tabs.page.html` then replace all HTML tags with this.
<ion-tabs>
<ion-tab tab="home">
<ion-router-outlet name="home"></ion-router-outlet>
</ion-tab>
<ion-tab tab="details">
<ion-router-outlet name="details"></ion-router-outlet>
</ion-tab>
<ion-tab tab="add">
<ion-router-outlet name="add"></ion-router-outlet>
</ion-tab>
<ion-tab tab="edit">
<ion-router-outlet name="edit"></ion-router-outlet>
</ion-tab>
<ion-tab-bar slot="bottom">
7
<ion-tab-button tab="add" href="/tabs/(add:add)">
<ion-icon name="add"></ion-icon>
<ion-label>Add</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
<ion-content>
<cdk-virtual-scroll-viewport cdkDropList itemSize="20" class="example-viewport"
(cdkDropListDropped)="drop($event)">
<ion-item *cdkVirtualFor="let p of products" class="example-item" href="/tabs/(details:
{{p._id}})" cdkDrag>
<ion-icon name="desktop" slot="start"></ion-icon>
{{p.prod_name}}
<div class="item-note" slot="end">
{{p.prod_price | currency}}
</div>
</ion-item>
</cdk-virtual-scroll-viewport>
</ion-content>
6. Ionic 4, Angular 7 and Cordova Tutorial: Display Data Details and Delete
Every time you click the list item in the List of data, you will be redirect to Details tab including the ID of the
selected data. Open and edit `src/app/details/` then add/replace this imports.
import { Component, OnInit } from '@angular/core';
import { LoadingController, AlertController } from '@ionic/angular';
import { ApiService } from '../api.service';
import { ActivatedRoute, Router } from '@angular/router';
import { Product } from '../product';
9
Inject above modules to the constructor.
constructor(public api: ApiService,
public loadingController: LoadingController,
public alertController: AlertController,
public route: ActivatedRoute,
public router: Router) {}
Add a variable before the constructor for hold Product data.
product:Product = { _id: null, prod_name: '', prod_desc: '', prod_price: null, updated_at:
null };
Add an asynchronous function to getting Product detail from API.
async getProduct() {
if(this.route.snapshot.paramMap.get('id') == 'null') {
this.presentAlertConfirm('You are not choosing an item from the list');
} else {
const loading = await this.loadingController.create({
message: 'Loading...'
});
await loading.present();
await this.api.getProduct(this.route.snapshot.paramMap.get('id'))
.subscribe(res => {
console.log(res);
this.product = res;
loading.dismiss();
}, err => {
console.log(err);
loading.dismiss();
});
}
}
Add an asynchronous function for display an alert.
async presentAlertConfirm(msg: string) {
const alert = await this.alertController.create({
header: 'Warning!',
message: msg,
buttons: [
{
text: 'Okay',
handler: () => {
this.router.navigate(['']);
}
}
]
});
await alert.present();
}
Call get product function from Angular 7 init function.
ngOnInit() {
this.getProduct();
10
}
Add the functions to delete the data.
async delete(id) {
const loading = await this.loadingController.create({
message: 'Loading...'
});
await loading.present();
await this.api.deleteProduct(id)
.subscribe(res => {
loading.dismiss();
this.router.navigate([ '/tabs', { outlets: { home: 'home' } } ]);
}, err => {
console.log(err);
loading.dismiss();
});
}
Next, open and edit `src/app/details/details.page.html` then replace all HTML tags with this.
<ion-header>
<ion-toolbar>
<ion-title>Details</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card>
<ion-card-header>
<ion-card-title>{{product.prod_name}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-item>
<p>Price:</p>
<p>{{product.prod_price | currency}}</p>
</ion-item>
<ion-item>
<p>Description:</p>
<p>{{product.prod_desc}}</p>
</ion-item>
<ion-button type="button" shape="round" color="primary" expand="block"
href="/tabs/(edit:{{product._id}})">Edit</ion-button>
<ion-button type="button" shape="round" color="danger" expand="block"
(click)="delete(product._id)">Delete</ion-button>
</ion-card-content>
</ion-card>
</ion-content>
11
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
Register the Reactive Form Module to the `@NgModule` imports array.
imports: [
IonicModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
RouterModule.forChild([{ path: '', component: EditPage }])
],
Next, open and edit `src/app/edit/edit.page.ts` then add/replace this imports.
import { Component, OnInit } from '@angular/core';
import { LoadingController, AlertController } from '@ionic/angular';
import { ApiService } from '../api.service';
import { ActivatedRoute, Router } from '@angular/router';
import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from
'@angular/forms';
import { Product } from '../product';
Add this constructor and inject above modules.
constructor(public api: ApiService,
public loadingController: LoadingController,
public alertController: AlertController,
public route: ActivatedRoute,
public router: Router,
private formBuilder: FormBuilder) {
}
Add the variables for hold current data, Form Group and Reactive Form controls.
productForm: FormGroup;
_id:any='';
prod_name:string='';
prod_desc:string='';
prod_price:number=null;
Add asynchronous function to get Product Detail.
async getProduct(id) {
if(this.route.snapshot.paramMap.get('id') == 'null') {
this.presentAlertConfirm('You are not choosing an item from the list');
} else {
const loading = await this.loadingController.create({
message: 'Loading...'
});
await loading.present();
await this.api.getProduct(id)
.subscribe(data => {
this._id = data._id;
this.productForm.setValue({
prod_name: data.prod_name,
prod_desc: data.prod_desc,
prod_price: data.prod_price
});
loading.dismiss();
12
}, err => {
console.log(err);
loading.dismiss();
});
}
}
Call that function inside Angular 7 init.
ngOnInit() {
this.getProduct(this.route.snapshot.params['id']);
this.productForm = this.formBuilder.group({
'prod_name' : [null, Validators.required],
'prod_desc' : [null, Validators.required],
'prod_price' : [null, Validators.required]
});
}
Add asynchronous function for handle form submit.
async onFormSubmit(form:NgForm) {
await this.api.updateProduct(this._id, form)
.subscribe(res => {
let id = res['_id'];
this.router.navigate([ '/tabs', { outlets: { details: id }} ]);
}, (err) => {
console.log(err);
}
);
}
Add asynchronous function to display an alert that calls on the first function.
async presentAlertConfirm(msg: string) {
const alert = await this.alertController.create({
header: 'Warning!',
message: msg,
buttons: [
{
text: 'Okay',
handler: () => {
this.router.navigate(['']);
}
}
]
});
await alert.present();
}
Next, open and edit `src/app/edit/edit.page.html` then replace all HTML tags with this.
<ion-header>
<ion-toolbar>
<ion-title>Edit</ion-title>
</ion-toolbar>
</ion-header>
13
<ion-content padding>
<form [formGroup]="productForm" (ngSubmit)="onFormSubmit(productForm.value)">
<ion-item>
<ion-label position="floating">Product Name</ion-label>
<ion-input type="text" formControlName="prod_name"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Product Price</ion-label>
<ion-input type="number" formControlName="prod_price"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Product Description</ion-label>
<ion-textarea formControlName="prod_desc"></ion-textarea>
</ion-item>
<ion-button type="submit" shape="round" color="primary" expand="block" [disabled]="!
productForm.valid">Submit</ion-button>
</form>
</ion-content>
14
productForm: FormGroup;
prod_name:string='';
prod_desc:string='';
prod_price:number=null;
Add Angular 7 init.
ngOnInit() {
this.productForm = this.formBuilder.group({
'prod_name' : [null, Validators.required],
'prod_desc' : [null, Validators.required],
'prod_price' : [null, Validators.required]
});
}
Add asynchronous function for handle form submit.
async onFormSubmit(form:NgForm) {
const loading = await this.loadingController.create({
message: 'Loading...'
});
await loading.present();
await this.api.addProduct(form)
.subscribe(res => {
let id = res['_id'];
loading.dismiss();
console.log(this.router);
this.router.navigate([ { outlets: { details: id } } ], { relativeTo:
this.route.parent });
}, (err) => {
console.log(err);
loading.dismiss();
});
}
Next, open and edit `src/app/edit/edit.page.html` then replace all HTML tags with this.
<ion-header>
<ion-toolbar>
<ion-title>
Add Product
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<form [formGroup]="productForm" (ngSubmit)="onFormSubmit(productForm.value)">
<ion-item>
<ion-label position="floating">Product Name</ion-label>
<ion-input type="text" formControlName="prod_name"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Product Price</ion-label>
<ion-input type="number" formControlName="prod_price"></ion-input>
</ion-item>
<ion-item>
15
<ion-label position="floating">Product Description</ion-label>
<ion-textarea formControlName="prod_desc"></ion-textarea>
</ion-item>
<ion-button type="submit" shape="round" color="primary" expand="block" [disabled]="!
productForm.valid">Submit</ion-button>
</form>
</ion-content>
9. Ionic 4, Angular 7 and Cordova Tutorial: Run and Test The App
Before running the Ionic 4 and Angular 7 application, first, you have run the Node.js, Express.js and MongoDB
RESTful API that previously downloaded. Type this commands in another terminal tab. We assume, you already
running the MongoDB server.
npm install
npm start
Now, we have to run the whole Ionic 4 and Angular 7 application to the browser first by type this command.
ionic serve -l
You can navigate the whole application, so it will similar like this.
16
17
To run on the devices, type this commands.
ionic cordova platform rm android
ionic cordova platform add android
ionic cordova run android
ionic cordova platform rm ios
ionic cordova platform add ios
ionic cordova run ios
That it's, the results of our experiment of using Angular 7 with Ionic 4 beta. To get the full working source code,
you can get from our GitHub.
We know that building beautifully designed Ionic apps from scratch can be frustrating and very time-consuming.
Check Ion2FullApp ELITE - The Complete Ionic 3 Starter App and save development and design time.
That just the basic. If you need more deep learning about Ionic, Angular, and Typescript, you can find the
following books:
Pro Typescript, Application-Scale Javascript Development
Learn Ionic 2, Develop Multi-platform Mobile Apps (Still compatible with Ionic 3)
Angular 4 Projects, Learn to Build Single Page Web Applications Using 70+ Projects
Or take the following course:
Learn Ionic 3 From Scratch
Master Ionic 3 with Ionic Native and Cordova Integrations
Ionic 3: Build A Complete Mobile Weather App From Scratch
Thanks!
18