Config
Introduction
This document shows the steps neede to work with REST API.
Guide
Step 1. Navigate to
MobileScaffold
folder, open integrated terminalStep 2. Run
$ ionic generate
Generate two new pages
pages/contact/contact-list
pages/contact/contact-detail
- Step 3. There are 6 auto-generated files: (* represents contact-list or contact-details)
- *-routing.module: manage routing
- *.module: Component module contains all the configuration
- *.page.html: UI template for the page
- *.page.css: Component style sheet. Can be used for custom style for your page
- *.page.spec.ts: Unit test go here
- *.page.ts: All the features code / logic code go here
- Step 4. Modify
contact-detail.page.html
<ion-header>
<ion-toolbar>
<ion-title>Contact detail</ion-title>
<ion-buttons slot="end">
<ion-menu-toggle>
<ion-button>
<ion-icon slot="icon-only" name="menu"></ion-icon>
</ion-button>
</ion-menu-toggle>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding page-home-content">
<section class="ion-text-center ion-margin-bottom">
<ion-avatar class="avatar-block">
<img src="/assets/images/avatar-rey.png" />
</ion-avatar>
</section>
<section class="ion-margin-bottom">
<ion-title>Name</ion-title>
<ion-input class="" required [placeholder]="'cw_mb_contact_placeholder' | translate" [(ngModel)]="contact.name">
</ion-input>
</section>
<section class="ion-margin-bottom">
<ion-title>Type</ion-title>
<ion-select placeholder="Select type" [(ngModel)]="contact.type">
<ion-select-option value="reporter">Reporter</ion-select-option>
<ion-select-option value="relevant">Relevant</ion-select-option>
<ion-select-option value="invitee">Invitee</ion-select-option>
</ion-select>
</section>
<section class="ion-margin-bottom">
<ion-title>Address</ion-title>
<ion-input required [placeholder]="'cw_mb_contact_placeholder' | translate" [(ngModel)]="contact.address">
</ion-input>
</section>
<ion-row class="ion-justify-content-around" *ngIf="!isAdding">
<ion-col size="3">
<ion-button size="medium" color="danger" type="button" class="text-transform-unset"
(click)="deleteContact()">
<ion-title>Delete</ion-title>
</ion-button>
</ion-col>
<ion-col size="3">
<ion-button size="medium" color="primary" type="button" class="text-transform-unset"
(click)="updateContact()">
<ion-title>Update</ion-title>
</ion-button>
</ion-col>
</ion-row>
<ion-row class="ion-justify-content-between" *ngIf="isAdding">
<ion-col size="3"></ion-col>
<ion-col size="3">
<ion-button size="medium" color="primary" type="button" class="text-transform-unset" (click)="addContact()">
<ion-title>Add</ion-title>
</ion-button>
</ion-col>
</ion-row>
</ion-content>
- Step 5. Modify
contact-detail.page.scss
.page-home-content {
.avatar-block {
display: inline-block;
}
}
- Step 6. Modify
contact-detail.page.ts
import { Component, OnInit } from '@angular/core';
import { ContactService } from '../contact.service';
import { ActivatedRoute } from '@angular/router';
import { Contact } from '../../../shared/model';
import { LoadingController } from '@ionic/angular';
@Component({
selector: 'app-contact-detail',
templateUrl: './contact-detail.page.html',
styleUrls: ['./contact-detail.page.scss'],
})
export class ContactDetailPage implements OnInit {
id: string;
contact: Contact = new Contact();
isAdding = false;
loading: any;
constructor(private contactService: ContactService, private route: ActivatedRoute, private loadingCtrl: LoadingController) { }
ngOnInit() {
this.contactService.contact$.subscribe((val) => {
this.contact = val;
});
this.id = this.route.snapshot.paramMap.get('id');
if (!this.id || this.id === '0') {
this.isAdding = true;
this.contactService.resetContactModel();
}
else {
this.getContactById();
}
}
async getContactById() {
await this.createAndPresentLoading();
this.contactService.getContactById(this.id)
.subscribe(
(val) => this.loading.dismiss(),
(err) => this.loading.dismiss()
);
}
deleteContact = async () => {
await this.createAndPresentLoading();
this.contactService.deleteContact(this.id)
.subscribe(
(val) => this.loading.dismiss(),
(err) => this.loading.dismiss()
);
}
updateContact = async () => {
await this.createAndPresentLoading();
this.contactService.updateContact(this.contact)
.subscribe(
(val) => this.loading.dismiss(),
(err) => this.loading.dismiss()
);
}
addContact = async () => {
await this.createAndPresentLoading();
this.contact.date = new Date();
this.contactService.addContact(this.contact)
.subscribe(
(val) => this.loading.dismiss(),
(err) => this.loading.dismiss()
);
}
async createAndPresentLoading() {
this.loading = await this.loadingCtrl.create({
message: 'Loading...',
spinner: 'circles'
});
this.loading.present();
}
}
Step 7. Modify contact-list.page.html
<ion-header>
<ion-toolbar>
<ion-title>Contact list</ion-title>
<ion-buttons slot="end">
<ion-menu-toggle>
<ion-button>
<ion-icon slot="icon-only" name="menu"></ion-icon>
</ion-button>
</ion-menu-toggle>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<section class="ion-padding-horizontal ion-text-right" style="margin-top: 4px;">
<ion-button size="medium" color="primary" type="button" class="text-transform-unset"
[routerLink]="['/menu/main/contacts', 0]">
<ion-icon name="add-outline" slot="start"></ion-icon>
<ion-title>Add</ion-title>
</ion-button>
<ion-button size="medium" color="primary" type="button" class="text-transform-unset" (click)="getContacts()">
<ion-icon name="reload-outline" slot="start"></ion-icon>
<ion-title>Reload</ion-title>
</ion-button>
</section>
<ion-list>
<ion-item *ngFor="let contact of contacts" [routerLink]="['/menu/main/contacts', contact.id]">
<ion-avatar slot="start">
<img src="/assets/images/avatar-rey.png" />
</ion-avatar>
<ion-label>
<h2>{{contact.name}}</h2>
<h3>{{contact.type}}</h3>
<p>{{contact.address}}</p>
</ion-label>
</ion-item>
</ion-list>
</ion-content>
Step 8. Modify contact-list.page.ts
import { Component, OnInit } from '@angular/core';
import { LoadingController } from '@ionic/angular';
import { ContactService } from '../contact.service';
@Component({
selector: 'app-contact-list',
templateUrl: './contact-list.page.html',
styleUrls: ['./contact-list.page.scss'],
})
export class ContactListPage implements OnInit {
contacts = [];
constructor(private contactService: ContactService, private loadingCtrl: LoadingController, public translate: TranslateService) { }
async ngOnInit() {
this.getContacts();
this.contactService.contacts$.subscribe((val) => {
this.contacts = val;
});
}
async getContacts() {
const loading = await this.loadingCtrl.create({
message: 'Loading...',
spinner: 'circles'
});
loading.present();
this.contactService.getContacts()
.subscribe(
(val) => loading.dismiss(),
(err) => loading.dismiss()
);
}
}
- Step 9. Generate
contact
service
CREATE src/app/pages/contact/contact.service. spec.ts (362 bytes)
CREATE src/app/pages/contact/contact.service.ts (136 bytes)
[OK] Generated service!
- Step 10. Modify
contact.service.ts
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { NavController } from '@ionic/angular';
import { BehaviorSubject, Observable, throwError, pipe } from 'rxjs';
import { catchError, filter, map } from 'rxjs/operators';
import { Contact } from 'src/app/shared/model';
import { AuthHttpService } from '../../auth/auth-http.service';
import { environment } from 'src/environments/environment';
@Injectable({
providedIn: 'root'
})
export class ContactService {
private contacts = new BehaviorSubject<Contact[] | null>([]);
public readonly contacts$ = this.contacts.asObservable();
private contact = new BehaviorSubject<Contact | null>(new Contact());
public readonly contact$ = this.contact.asObservable();
private static handleError(error: HttpErrorResponse): any {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
}
else {
console.error(`Backend returned code ${error.status}, ` + `body was: ${error.error}`);
}
return throwError('Something bad happened; please try again later.');
}
constructor(private autHttp: AuthHttpService, private navController: NavController) { }
changeData(data: any) {
this.contacts.next(data);
}
/**
*
* @param isNeedGoBack
*/
getContacts(isNeedGoBack?: boolean): Observable<any> {
return this.autHttp.get(`${environment.API_URL}/contacts`)
.pipe(
map(res => {
this.changeData(res);
if (isNeedGoBack) {
this.navController.back();
}
return res;
}),
catchError((err, cautch) => ContactService.handleError(err))
);
}
getContactById(id: string): Observable<any> {
if (!id || id === '0') {
this.contact.next(new Contact());
}
else {
return this.autHttp.get(`${environment.API_URL}/contact?Id=${id}`)
.pipe(
map((res: any) => {
this.contact.next(res);
return res;
}),
catchError((err, cautch) => ContactService.handleError(err))
);
}
}
deleteContact(id: string): Observable<any> {
const model = {
contactId: id
}
return this.autHttp.post(`${environment.API_URL}/contact/delete`, model)
.pipe(
map((res: any) => {
this.getContacts(true).subscribe();
return res;
}),
catchError((err, cautch) => ContactService.handleError(err))
);
}
updateContact(model: Contact): Observable<any> {
return this.autHttp.post(`${environment.API_URL}/contact/edit`, { ...model, contactId: model.id })
.pipe(
map((res: any) => {
this.getContacts(true).subscribe();
return res;
}),
catchError((err, cautch) => ContactService.handleError(err))
);
}
addContact(model: Contact): Observable<any> {
return this.autHttp.post(`${environment.API_URL}/contact`, model)
.pipe(
map((res: any) => {
this.getContacts(true).subscribe();
return res;
}),
catchError((err, cautch) => ContactService.handleError(err))
);
}
resetContactModel() {
this.contact.next(new Contact());
}
}