การส่งข้อมูลระหว่าง Component ใน Angular 7 โดยใช้ Service

By KDBEER | Last updated Dec 29, 2023
การส่งข้อมูลระหว่าง Component ใน Angular 7 โดยใช้ Service-5e19ba806a6e372a70f264ef

สวัสดีครับ ผมได้เจอคำถามเกี่ยวกับการใช้งาน Component ของ Angular และเจอปัญหาว่า เมื่อต้องทำงานหลายๆ Component เราจะมีวิธีการส่งข้อมูล หรือ Refresh ข้อมูลระหว่าง Component ยังไง

วิธีที่ผมจะนำมาแชร์เป็นวิธีง่ายๆ ครับ โดยการใช้งาน operator ของ RxJs ร่วมกับ service ของ angular หลักการคือ ผมจะสร้างตัวแปรที่เป็น data storeไว้ ซึ่งทุกๆ component ไม่ว่าจะเป็น module เดียวกันหรือคนละ module ก็สามารถดักจับการเปลี่ยนแปลงของข้อมูลก้อนนี้ได้ และนำค่านี้ไปใช้งานกับ component ของตัวเอง เอาละ มาเริ่มกันเลยครับ

source code

https://github.com/kdbeer/ng-service-communicate

Overview

ตัวอย่างนี้ ผมจะสร้าง component มาสอง component อันแรกฝั่งซ้ายมือ ทำหน้าที่เพิ่ม data ลงไปในลิสต์ list และ list จะไปแสดงที่ component ที่สองทางฝั่งขวามือ ซึ่ง component ที่สองจะสามารถลบลิสต์ที่ถูกเพิ่มได้ด้วย

Service

import { Injectable } from '@angular/core';
import { Subject, BehaviorSubject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AppService {
  rawData = [];

  private list = new BehaviorSubject<string[]>([]);
  readonly list$ = this.list.asObservable();

  constructor() {}

  addNewList(list) {
    console.log(list);
    this.rawData.push(list);
    this.list.next(this.rawData);
  }

  removeList(list) {
    this.rawData = this.rawData.filter(v => v !== list);
    this.list.next(this.rawData);
  }
}

จาก Code ด้านบนนี้ จะพบตัวแปรที่เป็นหัวใจของบทความนี้เลย ได้แก่

  1. rawData เป็นตัวแปรที่ใช้เก็บข้อมูลจริงๆ
  2. list เป็นตัวแปรชนิด Behavior Subject เป็นตัวแปรที่ทำหน้าที่คอยทำหน้าที่ update ตัวแปรทุกตัวที่มา observe มัน แต่ที่ behavior subject ต่างจาก subject ทั่วไป คือมันเป็น “values over time” มันจะไม่ emit ข้อมูลที่มันได้รับออกมามั่วๆ แต่มันจะเรียงตาม sequence ตามเวลาที่เข้ามาเท่านั้น ถ้าอ่านตรงๆ แล้วงงๆ ว่า “ข้อมูลที่รับมาคืออะไร” เลื่อนไปอ่านข้างล่างได้เลยครับ
  3. list$ เป็นตัวแปรชนิด Observable การทำงานของมันจำง่ายๆ ครับ เมื่อเวลา Behavior Subject ทำการ emit หรือกำลังพยายามบอกว่าตัวเองได้รับ data มาใหม่นะ ตัวแปร observable ก็จะส่งสัญญานไปกระตุ้นทุก component ที่ subscribe มันอยู่ ให้รู้ว่ามีการเปลี่ยนแปลงนะ นี่แหละครับการส่งข้อมูลระหว่าง component แบบ real time

“ข้อมูลที่รับมาคืออะไร”
จะเห็นว่าบรรทัด this.list.next(…) ที่อยู่ในฟังก์ชัน addNewList(…) กับ removeNewList(…) เป็นการส่งข้อมูลไป update subject ทำให้ข้อมูลมีการเปลี่ยนแปลง

Components

<form (ngSubmit)="addNewList()" #form="ngForm">
  <input type="text" [(ngModel)]="listName" name="listName" />
  <button type="submit">Add</button>
</form>
export class ComponentAComponent implements OnInit {
  listName: string;

  constructor(private as: AppService) {}

  ngOnInit() {}

  addNewList() {
    if (this.listName === '') {
      return;
    }

    this.as.addNewList(this.listName);
    this.listName = '';
  }
}

1.อัพเดทค่ากลาง

เริ่มจาก component a นะครับ เราจำเป็นต้อง Inject เอา AppService เข้ามา เพื่อที่เราจะได้ส่งข้อมูลเข้าไปหา ตัวแปร 3 ตัวหลักที่ผมกล่าวถึงเมื่อกี้ได้

ที่ฟังก์ชัน addNewList() มันทำการเรียก ฟังก์ชัน as.addNewList(…) ที่เป็นฟังก์ชั่นของ service พอฟังช์นั่นนี้ถูกเรียก มันก็จะไป update ให้ subject ไปอัพเดท observer และพอ component b รู้ว่ามีการเปลี่ยนแปลง มันก็จะนำค่าไปอัพเดทต่อไป ไปดูตัวอย่างกันต่อครับ อีกนิดเดียว

<ul>
  <li *ngFor="let item of list">
    {{ item }} : <button type="button" (click)="remove(item)">remove</button>
  </li>
</ul>
export class ComponentBComponent implements OnInit {
  list = [];

  constructor(private as: AppService) {}

  ngOnInit() {
    this.as.list$.subscribe(list => (this.list = list));
  }

  remove(list) {
    this.as.removeList(list);
  }
}

2. การรับรู้และแสดงผล

จากบรรทัดที่ 7 ของไฟล์ component-b.component.ts

this.as.list$.subscribe(list => (this.list = list));

มันก็คือการ subscribe ตัวแปรที่มีชนิดเป็น observable และพอมีการเปลี่ยนแปลงเกิดขึ้น ตัวแปร list ของ component นี้จะถูกอัพเดท และ template หรือไฟล์ html ก็จะ render ค่าที่อยู่ในตัวแปรลิสต์อัตโนมัต

3. การลบข้อมูล

this.as.removeList(list);

การลบข้อมูลก็ไม่ต่างอะไรจากการเพิ่มข้อมูลมากนัก เพียงแค่การจัดการกับตัวแปรที่เป็น rawValue ต่างกันแค่นั้น แต่เมื่อใดก็ตามที่ subject มันถูกอัพเดท ก็จะส่งสัญญานำไปบอกตัวแปร observable และก็ส่งสัญญานไปบอก component ที่ subscribe อีกที เราถึงได้มองเห็นว่าค่ามันเปลี่ยยนแปลงได้นั่นเอง

สรุป

ก็ได้อธิบายไปแล้วว่า behavior subject กับ subject รวมถึงการส่งข้อมูลระหว่าง component ทำงานอย่างไร เป็นตัวอย่างง่ายๆ ซึ่งก็หวังว่ามันจะช่วยให้ผู้อ่านได้รับคำตอบที่ต้องการไม่มากก็น้อย และถ้ามีข้อสงสัย ก็อย่างลังเลที่จะถามนะครับ แล้วพบกันใหม่ครับ

 

Reference

http://reactivex.io/rxjs/manual/overview.html#behaviorsubject

https://medium.com/@nutron/subjects-395051814e3d