Angular Services: Data Sharing & Logic Across Components

Introduction

In this article, we are going to utilize Angular Services. A Service is a class having certain operations for a specific purpose. We use services in Angular to share the data among components. In an application, the service is responsible for providing the data to the component. So, the sharing of data is also one of the responsibilities of the service. Another facility that the service provides is application logic. We create the service that has a certain logic and utilizes that in the component so as to make the component directly using the logic/operations without binding that logic to the component individually. We create a service for a certain request that interacts externally to get the data from somewhere and give that to the View. We can perform so many operations by using Services in Angular.

Prerequisites

  • HTML, CSS, and JS
  • Basic coding knowledge of TypeScript
  • Components

Let us create a sample TestApp. For this, you should have the below for the development environment installed.

  1. Node
  2. Npm (comes when you install node)
  3. Angular CLI
  4. Text Editor.

To create a new application, run the below command on your preferred location.

ng new TestApp

Once your command is completed, you will have a TestApp folder created inside your sample folder.

Note. See my previous article “Getting Started with Angular CLI” if you want to learn the installation and introduction from the basics and want to get started with the execution of a sample application.

Let us start with a simple application having details of students in two different components. Create two components.

  • >ng g c student-details
  • >ng g c student-marks

The following files will be added.

Services In Angular

Open student-details.component.ts and add the below code.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-student-details',
  templateUrl: './student-details.component.html',
  styleUrls: ['./student-details.component.css']
})
export class StudentDetailsComponent implements OnInit {

  public students = [
    {"id" : 1001, "name" : "Irshad", "marks" : 90},
    {"id" : 1002, "name" : "Imran", "marks" : 80},
    {"id" : 1003, "name" : "Rahul", "marks" : 70},
    {"id" : 1004, "name" : "Ajay", "marks" : 85},
    {"id" : 1005, "name" : "Sunny", "marks" : 60}
  ];

  constructor() { }

  ngOnInit() {
  }

}

Open student-details.component.html and add the below lines of code.

<h2>Student Details:</h2>
<div *ngFor="let stud of students">
  Id: {{stud.id}}, Name: {{stud.name}}
</div>

Open student-marks.component.ts and add the below lines.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-student-marks',
  templateUrl: './student-marks.component.html',
  styleUrls: ['./student-marks.component.css']
})
export class StudentMarksComponent implements OnInit {

  public students = [
    {"id" : 1001, "name" : "Irshad", "marks" : 90},
    {"id" : 1002, "name" : "Imran", "marks" : 80},
    {"id" : 1003, "name" : "Rahul", "marks" : 70},
    {"id" : 1004, "name" : "Ajay", "marks" : 85},
    {"id" : 1005, "name" : "Sunny", "marks" : 60}
  ];

  constructor() { }

  ngOnInit() {
  }

}

Open student-marks.component.html and add this code.

<h2>Marks Details:</h2>
<div *ngFor="let stud of students">
  Id : {{stud.id}}, Marks : {{stud.marks}}
</div>

Open app.component.html and add the following code.

<!-- The content below is only a placeholder and can be replaced. -->
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <app-student-details></app-student-details>
  <br>
  <app-student-marks></app-student-marks>
</div>

Run the application.

Angular

The above application is working but it is not a good programming practice. You can see that we have added the same set of data to both the files - student-details.component.ts and in student-marks.component.ts.

public students = [
  {"id" : 1001, "name" : "Irshad", "marks" : 90},
  {"id" : 1002, "name" : "Imran", "marks" : 80},
  {"id" : 1003, "name" : "Rahul", "marks" : 70},
  {"id" : 1004, "name" : "Ajay", "marks" : 85},
  {"id" : 1005, "name" : "Sunny", "marks" : 60}
];

This same data is being used in both the components, which means the component is not only responsible for displaying or working with the data, it is also taking the responsibility of generating the data, which actually should not be its responsibility. These components should only be responsible for using the given data. This is breaking the single responsibility rule of the programming.

Here comes Angular Services into the picture. We should have a service that will be injected into these two components and should solely be responsible for delivering the data to these components. These components should only perform one responsibility: dealing with how to use the data given by the service.

So, when we inject the service, the component will only use the data given by the Service instead of knowing how the data is coming from that service. This makes the service responsible for generating the data and components are responsible for making it display.

Let us start creating a service and use that in your application.

ng generate service student

Student

Open student.service.ts and add the below code.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class StudentService {
  students = [
    {"id" : 1001, "name" : "Irshad", "marks" : 90},
    {"id" : 1002, "name" : "Imran", "marks" : 80},
    {"id" : 1003, "name" : "Rahul", "marks" : 70},
    {"id" : 1004, "name" : "Ajay", "marks" : 85},
    {"id" : 1005, "name" : "Sunny", "marks" : 60}
  ];

  constructor() { }

  getStudents(){
    return this.students;
  }
}

Open app.module.ts and add these services to the provider.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Pipe } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { TestComponent } from './test/test.component';
import { StudentDetailsComponent } from './student-details/student-details.component';
import { StudentMarksComponent } from './student-marks/student-marks.component';

@Pipe({
  name: 'namePipe'
})

class NamePipe{
  transform(value : string, defaultValue : string) : string{
    if(value != ""){
      return value;
    } else {
      return defaultValue;
    }
  }
}

@NgModule({
  declarations: [
    AppComponent,
    TestComponent,
    NamePipe,
    StudentDetailsComponent,
    StudentMarksComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Open student-details.component.ts and add the below code.

import { Component, OnInit } from '@angular/core';
import { StudentService } from '../student.service';

@Component({
  selector: 'app-student-details',
  templateUrl: './student-details.component.html',
  styleUrls: ['./student-details.component.css']
})
export class StudentDetailsComponent implements OnInit {

  public students = [];

  constructor(private studentService : StudentService) {
    this.students = studentService.getStudents();
  }

  ngOnInit() {
  }

}

Open student-marks.component.ts and add this code.

import { Component, OnInit } from '@angular/core';
import { StudentService } from '../student.service';

@Component({
  selector: 'app-student-marks',
  templateUrl: './student-marks.component.html',
  styleUrls: ['./student-marks.component.css']
})
export class StudentMarksComponent implements OnInit {

  public students = [];

  constructor(private studentService : StudentService) {
    this.students = studentService.getStudents();
  }

  ngOnInit() {
  }

}

Run the application.

Run application

You have achieved the same thing that we got in our previous example, however, this time, the data is coming from a service and our component is only performing a single functionality, i.e., to render the data.


Similar Articles