บทที่ 4 Front-end Framework ด้วย Angular

สไลด์บทเรียน

วัตถุประสงค์

  1. อธิบายแนวคิด Front-end Framework และเหตุผลที่ใช้ Angular ได้
  2. เข้าใจโครงสร้างแอปแบบ Component-based Application ได้
  3. สร้าง Component, Template, Data Binding และ Directive ได้
  4. แยก logic ด้วย Service และเชื่อมต่อ API ด้วย HTTP Client ได้
  5. จัดหน้าเว็บหลายหน้าในแอปเดียวด้วย Routing และสร้าง Form เบื้องต้นได้

ภาพรวมบทเรียน

บทก่อนหน้าใช้ JavaScript จัดการ DOM และ event โดยตรง เมื่อแอปมีขนาดใหญ่ขึ้น การจัดการไฟล์ โครงสร้างหน้า state และการเรียก API จะซับซ้อนขึ้น Angular จึงช่วยวางโครงแอปให้เป็นระบบผ่าน component, service, router และเครื่องมือพัฒนาอย่าง Angular CLI

คำสำคัญของบทเรียน


1. ทำไมต้องใช้ Front-end Framework

เมื่อเว็บมีหลายหน้า หลาย component และต้องติดต่อ API หลายจุด การเขียน JavaScript แบบแยกไฟล์เองทั้งหมดอาจเริ่มดูแลยาก Front-end Framework ช่วยกำหนดรูปแบบการจัดโครงสร้างแอป ทำให้ทีมพัฒนาทำงานร่วมกันง่ายขึ้น

%%{init: {'theme': 'base', 'themeVariables': {
  'background': '#282828',
  'primaryColor': '#3c3836',
  'primaryTextColor': '#fbf1c7',
  'primaryBorderColor': '#fabd2f',
  'lineColor': '#83a598',
  'secondaryColor': '#504945',
  'tertiaryColor': '#665c54',
  'fontFamily': 'Arial'
}}}%%
flowchart LR
  A[HTML/CSS/JS
พื้นฐานเว็บ] --> B[Component
แบ่ง UI เป็นส่วน] B --> C[Service
แยก logic กลาง] C --> D[Router
จัดหน้าในแอป] D --> E[Angular App
แอปที่ดูแลได้เป็นระบบ]
ปัญหาในแอปใหญ่ Angular ช่วยอย่างไร
HTML และ JavaScript ปนกันมาก แยกเป็น component
logic เรียก API ซ้ำหลายหน้า แยกเป็น service
เปลี่ยนหน้าด้วย reload ทั้งเว็บ ใช้ router
form มี validation หลายเงื่อนไข ใช้ Angular Forms
โค้ดหลายคนเขียนไม่เหมือนกัน ใช้ CLI และโครงสร้างมาตรฐาน

2. Angular CLI และโครงสร้างโปรเจกต์

Angular CLI คือเครื่องมือ command line สำหรับสร้าง project, component, service, route และ build แอป ช่วยลดงานตั้งค่าเริ่มต้นและทำให้โครงสร้างไฟล์เป็นมาตรฐาน

# สร้างโปรเจกต์ Angular ใหม่
ng new product-dashboard

# เข้าโฟลเดอร์โปรเจกต์
cd product-dashboard

# เปิด development server
ng serve

# สร้าง component สำหรับหน้า products
ng generate component pages/products

# สร้าง service สำหรับจัดการข้อมูลสินค้า
ng generate service services/product

โครงสร้างไฟล์พื้นฐาน

ไฟล์/โฟลเดอร์ หน้าที่
src/main.ts จุดเริ่มต้นของแอป
src/app โค้ดหลักของ application
*.component.ts logic ของ component
*.component.html template ของ component
*.component.css style ของ component
*.service.ts logic กลางหรือการเรียก API
app.routes.ts กำหนดเส้นทางของหน้า

3. Component-based Application

Component เป็นแนวคิดหลักของ Angular โดยแบ่งหน้าเว็บเป็นชิ้นส่วนย่อยที่มีหน้าที่ชัดเจน เช่น header, sidebar, product list, product card และ footer วิธีนี้ทำให้แก้ไขง่ายและนำกลับมาใช้ซ้ำได้

%%{init: {'theme': 'base', 'themeVariables': {
  'background': '#282828',
  'primaryColor': '#3c3836',
  'primaryTextColor': '#fbf1c7',
  'primaryBorderColor': '#fabd2f',
  'lineColor': '#b8bb26',
  'secondaryColor': '#504945',
  'tertiaryColor': '#665c54',
  'fontFamily': 'Arial'
}}}%%
flowchart TD
  A[AppComponent
โครงหลัก] --> B[HeaderComponent
ส่วนหัว] A --> C[RouterOutlet
พื้นที่เปลี่ยนหน้า] C --> D[HomePage
หน้าแรก] C --> E[ProductsPage
หน้าสินค้า] E --> F[ProductCard
การ์ดสินค้า] A --> G[FooterComponent
ส่วนท้าย]
// product-card.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-product-card',
  templateUrl: './product-card.component.html',
  styleUrl: './product-card.component.css'
})
export class ProductCardComponent {
  // รับข้อมูลจาก component แม่
  @Input() name = '';
  @Input() price = 0;
}
<!-- product-card.component.html -->
<article class="product-card">
  <h2>{{ name }}</h2>
  <p>{{ price }} บาท</p>
</article>

4. Template และ Data Binding

Data Binding คือการเชื่อมข้อมูลระหว่าง component class กับ template ทำให้เมื่อข้อมูลเปลี่ยน หน้าเว็บเปลี่ยนตามได้ง่าย Angular มี binding หลายรูปแบบ เช่น interpolation, property binding, event binding และ two-way binding

รูปแบบ Syntax ใช้เมื่อ
Interpolation {{ value }} แสดงข้อความ
Property Binding [src]="imageUrl" ส่งค่าให้ property ของ element
Event Binding (click)="save()" เรียก method เมื่อเกิด event
Two-way Binding [(ngModel)]="keyword" เชื่อมค่า form กับตัวแปร
// products.component.ts
export class ProductsComponent {
  title = 'รายการสินค้า';
  keyword = '';

  search() {
    console.log(`ค้นหา: ${this.keyword}`);
  }
}
<!-- products.component.html -->
<h1>{{ title }}</h1>

<label for="keyword">คำค้นหา</label>
<input id="keyword" [(ngModel)]="keyword">

<button type="button" (click)="search()">ค้นหา</button>

5. Directive: ควบคุมโครงสร้างและพฤติกรรมใน Template

Directive คือคำสั่งพิเศษใน template ที่ช่วยควบคุม DOM เช่น แสดง/ซ่อน element วนรายการ หรือเปลี่ยน class ตามเงื่อนไข ใน Angular รุ่นใหม่นิยมใช้ control flow syntax เช่น @if และ @for

@if (products.length === 0) {
  <p>ยังไม่มีข้อมูลสินค้า</p>
} @else {
  <section class="product-grid">
    @for (product of products; track product.id) {
      <app-product-card
        [name]="product.name"
        [price]="product.price">
      </app-product-card>
    }
  </section>
}
คำสั่ง หน้าที่ ตัวอย่าง
@if แสดงตามเงื่อนไข แสดงข้อความเมื่อไม่มีข้อมูล
@for วนรายการ แสดง card ของสินค้า
[class.active] เปลี่ยน class highlight เมนูที่เลือก
[disabled] เปิด/ปิดการใช้งาน ปิดปุ่มเมื่อ form ไม่ถูกต้อง

6. Service และ Dependency Injection

Service ใช้แยก logic ที่ไม่ควรอยู่ใน component เช่น การเรียก API การจัดการข้อมูล หรือ function ที่ใช้หลายหน้า Angular ใช้ Dependency Injection เพื่อส่ง service เข้าไปให้ component ใช้งาน

%%{init: {'theme': 'base', 'themeVariables': {
  'background': '#282828',
  'primaryColor': '#3c3836',
  'primaryTextColor': '#fbf1c7',
  'primaryBorderColor': '#fabd2f',
  'lineColor': '#d3869b',
  'secondaryColor': '#504945',
  'tertiaryColor': '#665c54',
  'fontFamily': 'Arial'
}}}%%
flowchart LR
  A[ProductsComponent
หน้าแสดงสินค้า] --> B[ProductService
จัดการข้อมูล] B --> C[HttpClient
เรียก API] C --> D[Backend API
ข้อมูลสินค้า]
// product.service.ts
import { Injectable } from '@angular/core';

export interface Product {
  id: number;
  name: string;
  price: number;
}

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  private products: Product[] = [
    { id: 1, name: 'Keyboard', price: 850 },
    { id: 2, name: 'Mouse', price: 420 }
  ];

  getProducts() {
    return this.products;
  }
}
// products.component.ts
import { Component, inject } from '@angular/core';
import { ProductService } from '../services/product.service';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html'
})
export class ProductsComponent {
  private productService = inject(ProductService);

  products = this.productService.getProducts();
}

7. Routing: จัดหน้าใน Single-page Application

Routing ทำให้ Angular app มีหลายหน้า เช่น /, /products, /products/1 โดย browser ไม่ต้อง reload ทั้งเว็บไซต์ ผู้ใช้จึงรู้สึกว่าเปลี่ยนหน้าได้เร็วและต่อเนื่อง

// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { ProductsComponent } from './pages/products/products.component';
import { ProductDetailComponent } from './pages/product-detail/product-detail.component';

export const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'products', component: ProductsComponent },
  { path: 'products/:id', component: ProductDetailComponent }
];
<!-- app.component.html -->
<header>
  <a routerLink="/">Home</a>
  <a routerLink="/products">Products</a>
</header>

<router-outlet></router-outlet>

เปรียบเทียบ Routing กับการเปิดหน้าแบบเดิม

ประเด็น Traditional Page Angular Routing
การเปลี่ยนหน้า โหลด HTML ใหม่ทั้งหน้า เปลี่ยน component
ความเร็ว ช้ากว่าเมื่อโหลดซ้ำมาก เร็วและต่อเนื่อง
เหมาะกับ เว็บไซต์เอกสารธรรมดา Web application
การจัด state กระจายหลายหน้า จัดในแอปเดียว

8. Forms และ Validation

Angular รองรับการสร้าง form หลายแบบ ในบทนี้เริ่มจาก template-driven form เพื่อเข้าใจพื้นฐานการผูกค่าระหว่าง input กับตัวแปร และการตรวจสอบค่าก่อนส่งข้อมูล

<form #productForm="ngForm" (ngSubmit)="save()">
  <label for="name">ชื่อสินค้า</label>
  <input
    id="name"
    name="name"
    [(ngModel)]="productName"
    required
    minlength="3">

  <label for="price">ราคา</label>
  <input
    id="price"
    name="price"
    type="number"
    [(ngModel)]="price"
    required
    min="1">

  <button type="submit" [disabled]="productForm.invalid">
    บันทึก
  </button>
</form>
Validation ความหมาย
required ต้องกรอกข้อมูล
minlength ความยาวขั้นต่ำ
maxlength ความยาวสูงสุด
min ค่าต่ำสุด
max ค่าสูงสุด

9. HTTP Client และการโหลดข้อมูลจาก API

เมื่อต้องเชื่อมต่อ backend จริง Angular ใช้ HttpClient เพื่อส่ง request และรับข้อมูลจาก API โดยมักวาง logic ไว้ใน service แล้วให้ component เรียกใช้ service อีกที

// product-api.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ProductApiService {
  private http = inject(HttpClient);

  getProducts() {
    return this.http.get('/api/products');
  }
}

เวลาโหลดข้อมูลใน Angular app

T=R+S+V

10. ตัวอย่าง Mini Project: Product Dashboard

Mini project สำหรับบทนี้คือ Product Dashboard ประกอบด้วยหน้า Home, Products และ Product Detail พร้อม component อย่างน้อย 3 ส่วน

src/app/
  pages/
    home/
    products/
    product-detail/
  components/
    header/
    product-card/
    loading-state/
  services/
    product.service.ts
  app.routes.ts

ขอบเขตงานที่ควรทำได้

ส่วน รายละเอียด
Home Page อธิบายภาพรวมระบบ
Products Page แสดงรายการสินค้าเป็น card
Product Detail แสดงรายละเอียดจาก id ใน route
Product Service เก็บข้อมูลหรือเรียก API
Navigation ใช้ routerLink เปลี่ยนหน้า
Form เพิ่มช่องค้นหาหรือฟอร์มเพิ่มสินค้า

Checklist ก่อนส่งงานบทที่ 4

รายการตรวจ คำถามที่ต้องตอบ
Component แบ่ง UI เป็น component ที่หน้าที่ชัดเจนหรือไม่
Template ใช้ binding และ directive ถูกต้องหรือไม่
Service logic เรียกข้อมูลไม่ปนใน template หรือไม่
Routing มี route อย่างน้อย 2 หน้าและใช้ router-outlet หรือไม่
Form มี input, validation และปุ่ม submit หรือไม่
HTTP/API เตรียม service สำหรับเรียก API หรือข้อมูลจำลองหรือไม่
Maintainability ตั้งชื่อไฟล์ class และ selector อ่านง่ายหรือไม่

กิจกรรม

สร้าง Angular app ชื่อ Product Dashboard โดยมีเงื่อนไข:

  1. มี route อย่างน้อย 2 หน้า: Home และ Products
  2. มี component อย่างน้อย 3 ส่วน: Header, Product List, Product Card
  3. ใช้ service สำหรับจัดการข้อมูลสินค้า
  4. ใช้ binding แสดงชื่อและราคาสินค้า
  5. ใช้ @for หรือ *ngFor เพื่อวนรายการ
  6. มีฟอร์มหรือช่องค้นหาพร้อม validation เบื้องต้น

คำถามทบทวน

  1. Component ใน Angular ประกอบด้วยอะไรบ้าง
  2. Data Binding แต่ละแบบใช้ต่างกันอย่างไร
  3. Service เหมาะกับงานใด
  4. Routing ช่วยจัดโครงสร้างแอปอย่างไร
  5. ทำไมการเรียก API ควรแยกไว้ใน service

กลับรายวิชา