In Ionic Angular application contains the concept of ionic service: a class that contains business logic and it doesn’t have UI. The service class contains methods and properties that can be reused by injecting them across application components, directives, and other services.
In this tutorial, we have two objective. Firstly how to manage | retrieve| sending data to remote server using HTTP module. Second to allow sharing of data as simple demonstration of how we can use service to shared data among related and non related component.
What is Service ?
Service is a class that acts as a central repository, as a central business unit we could say something where you can store, where you can centralize code is shared across your application.
Angular services don’t have a view and it holds shareable or reusable code in our applications. Here we have listed some of the most important reasons why we need service in an Ionic application.
- Managing data state: For a small and medium application, we can use service and Ngrx library to manage the state of data across the application. In the large application, we can use Ngrx for reactive state management of data in Angular.
- Retrieving and sending data to remote server using REST API through Angular HTTP module.
- Centralize code containing business logic which shared accross application containing related and unrelated component.
- Sharing data: sharing data across components, especially among not related components (parent/child relationship among components
Setting and configure Ionic service example. ?
We can create an ionic service manually or by using ionic CLI to generate a new service. Let first create an Ionic application and use a blank template. We also need to create a service and we need a few pages to demonstrate HTTP requests.
ionic start sharedService blank --type=angular
cd serviceApp
ionic generate service serviceName
Let create a todo, edit, and a new todo page, we don’t need a home page. It is good practice to create a service folder for page, service, model, and so on.
ionic g page pages/todos
ionic g page pages/editTodo
ionic g page pages/todo
In our HTTP request, we are performing a strict type request on different HTTP methods. For that, we need to create an interface of todo, let create folder models and add todo.model.ts file with the following type.
export interface ITodo {
id?: string;
task: string;
status: string;
}
Configure routing module
We have created a few pages, we need to configure routing for these pages to demonstrate HTTP methods and let edit the app.routing.module.ts file
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{
path: 'todos',
loadChildren: () => import('./pages/todos/todos.module')
.then(m => m.TodosPageModule)
},
{
path: '',
redirectTo: 'todos',
pathMatch: 'full'
},
{
path: 'todo',
loadChildren: () => import('./pages/todo/todo.module')
.then(m => m.TodoPageModule)
},
{
path: 'todo/:id',
loadChildren: () => import('./pages/edit-todo/edit-todo.module')
.then(m => m.EditTodoPageModule)
}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here is this ionic tutorial we won’t discuss on Ionic Angular routing, will only focus on service functionalities.
Import HTTP and Forms module
We need HttpClientModule and FormsModule to demonstrate how we can use this module to demonstrate HTTP activities and let edit the app.module.ts file.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
HttpClientModule,
FormsModule
],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
Create dummy data
We need a database where we can retrieve, update, delete and add a new todo. Let create dummy data in assets/data/todos.json
{
"todos": [
{
"id": "1",
"task": "Meditation at 7 am",
"status": true
},
{
"id": "2",
"task": "Task 2",
"status": true
},
{
"id": "3",
"task": "Task 3 ",
"status": false
},
{
"id": "4",
"task": "Todo 4",
"status": true
}
]
}
Setting remote server
Setting up the server and adding data to the database will make our tutorial very long. We’ll use JSON Server to allow us to make fake HTTP requests without any coding and let install it globally.
In our Ionic service, we communicate remote server via an HTTP client module, we can use the ngx-restangular library also. We can use an Angular FireModule, which is built specifically for Firebase. The AngularFire library uses Firebase’s regular JavaScript/Web SDK under the hood
npm install json-server
All the HTTP requests to JSON Server are the same as Node-based express-js. To run the fake server, we need to run the command below on the terminal.
json-server src/assets/data/todos.json
Here is a screenshot of our fake server data.
We have already created a service class to request HTTP requests to a remote server. In the HTTP Service, we’ll encapsulate some logic that helps manage the list of todos into service, edit, delete and create new todos using the HttpClient service from Angular.
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ITodo } from '../models/todo.model';
const URL_PREFIX = "http://localhost:3000";
@Injectable({
providedIn: 'root'
})
export class TodosService {
constructor(private http: HttpClient) { }
getTodos(): Observable<Array<ITodo>> {
return this.http.get<Array<ITodo>>(`${URL_PREFIX}/todos`,);
}
getTodo(id: string): Observable<ITodo> {
return this.http.get<ITodo>(`${URL_PREFIX}/todos/${id}`);
}
addTodo(todo: ITodo) {
debugger
return this.http.post(`${URL_PREFIX}/todos`, todo)
.pipe(
catchError((error: HttpErrorResponse) => {
console.log(error.message);
return throwError("Error while creating a todo" + error.message);
}));
}
updateTodo(todo: ITodo, id: string): Observable<ITodo> {
return this.http.put<ITodo>(`${URL_PREFIX}/todos/${id}`, todo)
.pipe(
catchError((error: HttpErrorResponse) => {
// this.errorHandler.log("Error while updating a todo", error);
console.log(error.message);
return throwError("Error while updating a todo " + error.message);
}));
}
deleteTodo(id: string) {
return this.http.delete(`${URL_PREFIX}/todos/${id}`).pipe(
catchError((error: HttpErrorResponse) => {
console.log(error.message);
return throwError("Error while deleting a todo " + error.message);
}));
}
}
Consuming Ionic service for HTTP request
We have learned that service classes contain reusable code and all our remote servers are kept in the service class and components are consumers of service. Now let’s first demonstrate how to use the HTTP GET method to retrieve all todo lists in the todos.component.ts file.
HTTP GET and DELETE method
import { Component, OnInit } from '@angular/core';
import { ITodo } from 'src/app/models/todo.model';
import { TodosService } from 'src/app/services/todos.service';
@Component({
selector: 'app-todos',
templateUrl: './todos.page.html',
styleUrls: ['./todos.page.scss'],
})
export class TodosPage implements OnInit {
todos: ITodo[] = [];
constructor(private todoService: TodosService) { }
ngOnInit(): void {
debugger
this.todoService.getTodos()
.subscribe((data: ITodo[]) => {
this.todos = data
});
}
deleteTodo(todo: ITodo) {
let id = todo.id ? todo.id : '';
this.todoService.deleteTodo(id).subscribe(() => {
alert('Delete todo : ');
})
}
}
Edit the todos.component.html template to add an ionic grid component to iterate through each todos list.
<ion-header>
<ion-toolbar color="primary">
<ion-title size="small">Todos : HTTP GET method</ion-title>
<ion-buttons slot="end">
<ion-icon slot="start" name="add" routerLink="/todo"></ion-icon>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
<ion-grid fixed>
<ion-row class="header">
<ion-col>S.No</ion-col>
<ion-col>Task</ion-col>
<ion-col>Status</ion-col>
<ion-col>Edit</ion-col>
<ion-col>Delete</ion-col>
</ion-row>
</ion-grid>
</ion-item>
<ion-item *ngFor="let todo of todos; index as i">
<ion-grid>
<ion-row>
<ion-col>{{ i + 1 }}</ion-col>
<ion-col>{{ todo.task }}</ion-col>
<ion-col>
<span *ngIf="todo.status">Completed</span>
<span *ngIf="!todo.status">Pending</span>
</ion-col>
<ion-col>
<a [routerLink]="'/todo/' + todo.id" size="small" shape="round">
Edit
</a>
</ion-col>
<ion-col>
<ion-icon (click)="deleteTodo(todo)" name="trash-outline" color="danger"></ion-icon>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
</ion-list>
</ion-content>
Http POST method
In our todo component, we have used the HTTP POST method to add a new todo. Let edit the todo.component.ts file to implement to add a new todo.
In a real remote server, we don’t need to add an id, this is fake server to demonstrate HTTP requests. Let edit the todo component to implement adding new todo.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { ITodo } from 'src/app/models/todo.model';
import { TodosService } from 'src/app/services/todos.service';
@Component({
selector: 'app-todo',
templateUrl: './todo.page.html',
styleUrls: ['./todo.page.scss'],
})
export class TodoPage {
todo: ITodo = { id: '', task: '', status: false }
constructor(
private router: Router,
private todoService: TodosService) { }
addTodo(todo: ITodo) {
this.todoService.addTodo(todo).subscribe(() => {
alert('Add new task successful' + todo);
this.router.navigateByUrl('/');
})
}
}
Let’s edit the todo component template to add a form to add a new todo to our remote server.
<ion-header>
<ion-toolbar color="primary">
<ion-title size="small">Add new todo</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
<form #f="ngForm" novalidate (ngSubmit)="addTodo(f.value)">
<ion-list>
<ion-item>
<ion-label position="floating">Todo ID</ion-label>
<ion-input type="text" name="id" required
[(ngModel)]="todo.id" #idCtrl="ngModel" required></ion-input>
</ion-item>
<ion-text color="danger" *ngIf="!idCtrl.valid && idCtrl.touched">
<ion-text color="danger">Todo ID is required</ion-text>
</ion-text>
<ion-item>
<ion-label position="floating">Task</ion-label>
<ion-input type="text" name="task" required
[(ngModel)]="todo.task" #taskCtrl="ngModel" required></ion-input>
</ion-item>
<ion-text color="danger" *ngIf="!taskCtrl.valid && taskCtrl.touched">
<ion-text color="danger">Todo task is required</ion-text>
</ion-text>
<ion-item>
<ion-label>Agree to terms and conditions</ion-label>
<ion-toggle [(ngModel)]="todo.status" name="status" type="button">
</ion-toggle>
</ion-item>
<ion-item class="ion-float-right" lines="none">
<ion-button type="submit" size="small" [disabled]="!f.valid">
Submit
</ion-button>
</ion-item>
</ion-list>
</form>
</div>
</ion-content>
HTTP POST method
We can use the HTTP POST method to edit a todo, let’s edit the edit-todo.component.ts to implement HTTP POST methods.
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ITodo } from 'src/app/models/todo.model';
import { TodosService } from 'src/app/services/todos.service';
@Component({
selector: 'app-edit-todo',
templateUrl: './edit-todo.page.html',
styleUrls: ['./edit-todo.page.scss'],
})
export class EditTodoPage implements OnInit {
todo: ITodo = { id: '', task: '', status: false };
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private todoService: TodosService
) { }
ngOnInit() {
let id = this.activatedRoute.snapshot.params['id'];
if (id) {
this.todoService.getTodo(id).subscribe((data: any) => {
this.todo = {
id: data.id,
task: data.task,
status: data.status
}
})
}
}
updateTodo(todo: ITodo) {
this.todoService.updateTodo(todo, this.todo.id)
.subscribe(() => {
alert('Successful update');
this.router.navigateByUrl('todos');
})
}
}
<ion-header>
<ion-toolbar color="primary">
<ion-title size="small">Edit todo : {{ todo?.task}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
<form #f="ngForm" novalidate (ngSubmit)="updateTodo(f.value)">
<ion-list>
<ion-item>
<ion-label position="floating">Todo ID</ion-label>
<ion-input type="text" name="id" required
[(ngModel)]="todo.id" #idCtrl="ngModel" required>
</ion-input>
</ion-item>
<ion-text color="danger" *ngIf="!idCtrl.valid && idCtrl.touched">
<ion-text color="danger">Todo ID is required</ion-text>
</ion-text>
<ion-item>
<ion-label position="floating">Task</ion-label>
<ion-input type="text" name="task" required
[(ngModel)]="todo.task" #taskCtrl="ngModel" required>
</ion-input>
</ion-item>
<ion-text color="danger" *ngIf="!taskCtrl.valid && taskCtrl.touched">
<ion-text color="danger">Todo task is required</ion-text>
</ion-text>
<ion-item>
<ion-label>Agree to terms and conditions</ion-label>
<ion-toggle [(ngModel)]="todo.status" name="status" type="button">
</ion-toggle>
</ion-item>
<ion-item class="ion-float-right" lines="none">
<ion-button type="submit" size="small" [disabled]="!f.valid">
Submit
</ion-button>
</ion-item>
</ion-list>
</form>
</div>
</ion-content>
Example on how to use service in ionic to share data ?
In Ionic Angular, the components can communicate with each other in many ways for parent/child-related components we can use input and even binding for sharing data.
With service, we can easily share data among related and nonrelated components. In this example, we are creating a service called userService and by using this service when we change the data on the home page and change data can be displayed on a different page called confirm page.
On the home page, we display user information from the service and add a new user information name and age field to the service user.service.ts. We have a confirmed button and clicking on confirm on the home page will route us to confirm page where we can data of the home page from userService.
Create confirm page and user service as
>> ionic generate page confirm
>> ionic generate service services/user
Edit user.service.ts file and add the get/set method to do additional processing when other pages access or set the variables in this common class.
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
private _name: string;
private _age: number;
get name() {
return this._name;
}
set name(name: string) {
this._name = name;
}
get age() {
return this._age;
}
set age(age: number) {
this._age = age;
}
}
Edit in home.page.html template file to add | edit user information.
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Ionic 6 Service
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<div class="ion-padding">
<ion-card>
<ion-card-header>
<ion-card-title>What you are entering</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-badge color="secondary">Name</ion-badge>{{ user.name }}<br /><br />
<ion-badge color="tertiary">Age</ion-badge> {{ user.age }}
</ion-card-content>
</ion-card>
<ion-list>
<ion-item>
<ion-label position="fixed">Name</ion-label>
<ion-input type="text" [(ngModel)]="user.name"></ion-input>
</ion-item>
<ion-item>
<ion-label position="fixed">Age</ion-label>
<ion-input type="number" [(ngModel)]="user.age"></ion-input>
</ion-item>
<ion-item class="ion-float-right" lines="none">
<ion-button color="primary" [routerLink]="'/confirm'">Confirm</ion-button>
</ion-item>
</ion-list>
</div>
</ion-content>
Edit n home.page.ts file where we have to inject userService service on our page so that we can use it.
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
user: any;
constructor(private userService: UserService) { }
ngOnInit() {
this.user = this.userService;
}
}
Edit the confirm.page.html template to display data from the home page.
<ion-header>
<ion-toolbar>
<ion-title>Confirm</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card>
<ion-card-header>
<ion-card-title>Please confirm your profile</ion-card-title>
</ion-card-header>
<ion-card-content>
{{ user.name }} is {{ user.age }} years old
</ion-card-content>
<ion-item float-right>
<ion-button color="primary" [routerLink]="'/home'">Ok</ion-button>
</ion-item>
</ion-card>
</ion-content>
Edit confirm.page.ts file
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
@Component({
selector: 'app-confirm',
templateUrl: './confirm.page.html',
styleUrls: ['./confirm.page.scss'],
})
export class ConfirmPage implements OnInit {
user: any;
constructor(private userService: UserService) { }
ngOnInit() {
this.user = this.userService;
}
}
Conclusion
We have completed the ionic service, why we need it, and how we can use it to share data among different components. I hope you got some idea on Ionic service usage and how to implement it.
Related posts
- How to implement an ionic slider
- Complete guide on an ionic grid with an example
- How to implement an ionic alert controller.
- How to implement an ionic table with pagination.
- How to use ionic skeleton component.
- How to create a different ionic list.