Angular Observable – Part 5

Pada modul ini kita akan bahas penggunaan subject. Subject adalah tipe observable khusus yang dapat melakukan melakukan multicast value ke lebih dari satu observers.

Untuk contoh penggunaanya, dengan skenario sebuah button yang diclick, akan menampilkan tulisan.

Pertama, kita akan gunakan dahulu pendekatan eventEmiter yang sudah dibahas pada module sebelumnya. Setelah itu kita ubah menggunakan subject.

Buka file user.component.html, kemudian tambahkan element button.

<p>User with <strong>ID {{ id }}</strong> was loaded</p>
<button class="btn btn-primary" (click)="onClick()">Click Me</button>

Teks yang akan ditampilkan kita simpan di app.component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <a routerLink="/">Home</a> |
      <a [routerLink]="['user', 1]">
        User 1
      </a>
      |
      <a [routerLink]="['user', 2]">
        User 2
      </a>
    </div>
  </div>
  <hr />
  <!-- akan ditampilkan jika button di click-->
  <h3 *ngIf="userClicked">Button Clicked</h3> 
  <hr />
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <router-outlet></router-outlet>
    </div>
  </div>
</div>

Berikutnya kita buat service untuk data passing. Buat file baru user.service.ts

import { Injectable } from "@angular/core";
import { EventEmitter } from "@angular/core";

@Injectable({providedIn: 'root'})
export class UserService{
    buttonClicked = new EventEmitter<boolean>();

}

Service diatas kita inject pada user.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { UserService } from './user.service';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  id!: number;

  constructor(private route: ActivatedRoute, private userServ: UserService) {
  }

  ngOnInit() {
    this.route.params.subscribe((params: Params) => {
      this.id = +params.id;
    });
  }

  onClick(){
    this.userServ.buttonClicked.emit(true);
  }
}

Kemudian buka file app.component.ts, dimana kita akan subscribe perubahan data ketika button diclick.

import { Component, OnInit } from '@angular/core';
import { UserService } from './user/user.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  userClicked = false;
  constructor(private userServ : UserService) {}

  ngOnInit() {
    this.userServ.buttonClicked.subscribe(isclicked =>{
      this.userClicked = isclicked;
    });
  }
}

Jika Kita jalankan aplikasi, seusai ekspektasi, tulisan Button Clicked akan ditampilkan.

Berikutnya kita ubah kode diatas untuk menggunakan subject. Perubahan yang dilakukan cukup minimal.

Buka file user.service.ts, lalu ganti menggunakan subject.

import { Injectable } from "@angular/core";
//tidak digunakan lagi, karena diubah menggunakan subject
//import { EventEmitter } from "@angular/core";
import { Subject } from "rxjs";

@Injectable({providedIn: 'root'})
export class UserService{
    //pendekatan eventEmiter
    //buttonClicked = new EventEmitter<boolean>();
    
    //pendekatan subject
    buttonClicked = new Subject<boolean>();

}

Buka file user.component.ts, ubah code event emiter.

Perhatian, karena subject adalah observable, maka untuk emit value digunakan method next (silakan lihat modul sebelumnya). Jadi dapat dikatakan, subject adalah observable yang aktif, dimana kita bisa memanggil perintah next diluar object observable.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { UserService } from './user.service';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  id!: number;

  constructor(private route: ActivatedRoute, private userServ: UserService) {
  }

  ngOnInit() {
    this.route.params.subscribe((params: Params) => {
      this.id = +params.id;
    });
  }

  onClick(){
    //pendekatan eventemiter
    //this.userServ.buttonClicked.emit(true);
    
    //pendekatan subject
    this.userServ.buttonClicked.next(true);
  }
}

Nah, sekarang kita sudah menggunakan subject. Apabila Anda jalankan, button tetap berfungsi seperti semula.

Hal penting yang harus diperhatikan adalah, karena berupa custom observable, maka kita perlu implementasikan onDestroy untuk mencegah memory leak.

Buka file app.component.ts, lalu tambahkan method onDestroy

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { UserService } from './user/user.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
  userClicked = false;
  private clickedSub!  : Subscription;

  constructor(private userServ : UserService) {}

  ngOnInit() {
    this.clickedSub = this.userServ.buttonClicked.subscribe(isclicked =>{
      this.userClicked = isclicked;
    });
  }

  ngOnDestroy(): void {
    this.clickedSub.unsubscribe();
  }
}

Jika aplikasi yang Anda buat memiliki skenario seperti diatas, yaitu komunikasi antar component melalui service, dimana ada component yang akan melakukan subscribe untuk mendapatkan perubahan, maka disarankan menggunakan subject (jangan digunakan eventEmiter).

Dibandingkan pendekatan eventEmiter, subject lebih efisien dan selain itu, kita dapat gunakan operator yang sudah disediakan oleh rxjs.

Sharing is caring:

1 thought on “Angular Observable – Part 5”

Leave a Comment