How to implement Ionic service and its uses?

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.

Ionic service http example

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.

  1. 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.
  2. Retrieving and sending data to remote server using REST API through Angular HTTP module.
  3. Centralize code containing business logic which shared accross application containing related and unrelated component.
  4. 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 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.

Ionic service http request

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 first demonstrate how to use HTTP GET method to retrieve all todo list in todos.component.ts file.

HTTP GET and DELETE method

Ionic service http example


In the todo component template, we have used for structure directive to iterate through each loop. We also had two buttons, one to delete a todo and the edit button will navigate us to the edit.todo.component to allow the edition of a todo.
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 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.

Ionic service httpGET method

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 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 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.

ionic service example

Create confirm page and user service as
>> ionic generate page confirm
>> ionic generate service services/user
Edit user.service.ts file and add 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

Spread the love

Leave a Comment

Your email address will not be published.

Scroll to Top