Service: การสร้างและแชร์ข้อมูลระหว่าง Component

Service คือ Class ที่ใช้เก็บ Business Logic, ดึงข้อมูล, คำนวณ หรือแชร์ข้อมูลระหว่าง Component เพื่อให้ Component เน้นหน้าที่แสดงผลและรับ interaction จากผู้ใช้

Timeline/ประวัติศาสตร์

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
  subgraph Era1["ยุค Component หนัก / Fat Component"]
    A["Logic อยู่ใน Component
ดูแลยาก"] end subgraph Era2["ยุค Service Layer / Service Pattern"] B["แยก Logic
Separation of Concerns"] C["Shared Data
แชร์ข้อมูลข้าม Component"] end subgraph Era3["ยุค Reactive State / RxJS State"] D["BehaviorSubject
เก็บค่าล่าสุด"] E["Observable State
Subscribe เพื่ออัปเดต UI"] end A --> B --> C --> D --> E

แนวคิดสำคัญ

ตารางเปรียบเทียบการแชร์ข้อมูล

วิธี เหมาะกับ ข้อจำกัด
@Input() Parent ส่งข้อมูลให้ Child ใช้กับ Component ที่สัมพันธ์กัน
@Output() Child ส่ง Event ให้ Parent ต้องมีสายสัมพันธ์ใน Tree
Service + BehaviorSubject Component ไม่สัมพันธ์กัน ต้องจัดการ State ให้ชัดเจน
Route State ส่งข้อมูลผ่าน Navigation ไม่เหมาะกับ State ซับซ้อน

Mermaid Diagram: Shared State ผ่าน Service

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
  A["Component A
ผู้แก้ข้อมูล"] --> B["UserService
Shared State"] B --> C["BehaviorSubject
ค่าล่าสุด"] C --> D["Component B
ผู้แสดงผล"] C --> E["Component C
ผู้ใช้ข้อมูลร่วม"]

สมการคณิตศาสตร์: จำนวนการส่งต่อข้อมูล

P = n - 1

Code Example

// user.service.ts
// Service แชร์ข้อมูลผู้ใช้ด้วย BehaviorSubject
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

export interface User {
  id: number;
  name: string;
}

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private userSubject = new BehaviorSubject<User | null>(null);

  // เปิดเป็น Observable เพื่อไม่ให้ Component แก้ Subject โดยตรง
  user$: Observable<User | null> = this.userSubject.asObservable();

  setUser(user: User): void {
    this.userSubject.next(user);
  }

  clearUser(): void {
    this.userSubject.next(null);
  }
}
// profile.component.ts
// Component เรียก setUser เพื่ออัปเดต Shared State
import { Component } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-profile',
  template: `<button (click)="login()">Login</button>`
})
export class ProfileComponent {
  constructor(private userService: UserService) {}

  login(): void {
    this.userService.setUser({ id: 1, name: 'Suda' });
  }
}

// ตัวอย่างการใช้งาน:
// Component อื่นสามารถ subscribe userService.user$ เพื่อรับค่าล่าสุด

กิจกรรมท้ายบท

  1. สร้าง UserService
  2. ใช้ BehaviorSubject เก็บข้อมูลผู้ใช้
  3. สร้าง Component หนึ่งสำหรับแก้ชื่อผู้ใช้
  4. สร้างอีก Component สำหรับแสดงชื่อผู้ใช้

กลับสัปดาห์ที่ 8