การใช้งาน Build in directive ที่ใช้บ่อย ใน Angular

เขียนเมื่อ 6 ปีก่อน โดย Ninenik Narkdee
template syntax ngswitch ngstyle build in directive ngmodel ngclass ngif ngfor

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ template syntax ngswitch ngstyle build in directive ngmodel ngclass ngif ngfor

ดูแล้ว 16,875 ครั้ง


สำหรับเนื้อหาของตอนนี้เราจะยังอยู่เกี่ยวกับเรื่องของการใช้งาน template หรือส่วนจัดการที่เกัยวกับการ
ใช้งาน template ต่อจากบทความตอนที่แล้ว
 
"ทบทวนบทความตอนที่แล้วได้ที่"
การเชื่อมโยงข้อมูล Data Binding รูปแบบต่างๆ ใน Angular 
 
โดยหัวข้อหลักๆ ที่เราจะศึกษาคือ 
  • การใช้งาน Build in directive
  • การใช้งาน Template reference variable
  • การใช้งาน Input outpout property
 

การใช้งาน Build in directive

 
เรามาทำความเข้าใจเพิ่มกับสองสิ่งนี้กันเล็กน้อยก่อนระหว่าง HTML กับ DOM
DOM คือ โมเดลของ Document Object ที่สามารถจัดการปรับเปลี่ยนค่าต่างๆ ของตัวมันเองได้
โดยทั่วไปจะใช้ JavaSript 
HTML คือ เป็นโครงสร้างภาษาสำหรับแสดง DOM element ประเภทต่างๆ ในรูปแบบของข้อความ 
 
สมมติโครงสร้าง HTML  ของเราเป็นดังนี้
 
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Document</title>
</head>

<body>
</body>
</html>
 
DOM ของโครงสร้างภาษาข้างต้น ก็คือ document (Document Object)
DOM element แต่ละตัวถูกแสดงด้วยภาษา HTML ที่เรียกว่า HTML tag
DOM ของ <body> ก็คือ document.body
DOM ของ <head> ก็คือ document.head 
นอกจากนั้นยังสามารถใช้ JavaScript ในการอ้างอิงถึง DOM ได้ด้วยเช่น 
 
document.getElementsByTagName("body")
document.getElementsByTagName("head")
 
โดย HTML เป็นโครงสร้างภาษาที่ถูกกำหนดจากหน่วยงานที่กำกับดูแลในส่วนที่ มีรูปแบบและโครงสร้าง
เป็นมาตรฐาน
 
ส่วน Directive ที่เรากำลังจะใช้งาน ก็คือโครงสร้างภาษาคล้ายๆ กับ HTML แต่เป็นโครงสร้างภาษาที่เรา
กำหนดรูปแบบของ tag ต่างๆ ขึ้นมาเอง มี DOM element สามารถจัดการปรับเปลี่ยนค่าได้
 
โดยใน Angular จะมี Directive อยู่ด้วยกัน 3 ประเภท
1. Component เป็น directive ที่มีการใช้งานร่วมกับ template
2. Structural directive เป็น directive สำหรับปรับเปลี่ยนโครงสร้างของ DOM โดยการเพิ่มหรือลบ DOM element
3. Attribute directive เป็น directive สำหรับปรับเปลี่ยนรูปแบบหน้าตาหรือการทำงาน ของ element, component 
หรือ directive อื่นๆ
 
ในส่วนนี้เราจะมาดูเฉพาะส่วนของ Build-in directive ที่มีการใช้งานบ่อย ซึ่งอยู่ในประเภท Attribute directive 
และ Structural directive
 

 

การใช้งาน Built-in attribute directives

 
Attribute directive จะคอยสังเกตพฤติการณ์การเปลี่ยนเปลงของ HTML element, attribute, property
และ component   โดยปกติถูกนำมาใช้เป็น attribute ของ HTML 
ใน Angular module หลายๆ ตัว เช่น RouterModule และ FormsModule (FormModule เราได้เจอมาบ้างแล้ว)
ล่วนมี attribute ของตัวเอง แต่ส่วนที่เราจะแนะนำในที่นี้คือ attribute directive ที่มีการใช้กันบ่อยโดยทั่วไป
ประกอบไปด้วย
 
  • NgClass - ใช้สำหรับเพิ่มหรือลบ กลุ่มรายการของ CSS class
  • NgStyle - ใช้สำหรับเพิ่มหรือลบ กลุ่มรายการของ style property ของ HTML 
  • NgModel - ใช้สำหรับการเชื่อมโยงข้อมูลแบบสองทิศทาง ใน HTML form element
 
 

การใช้งาน NgClass

 
เราสามารถควบคุมการแสดงผลของ element ต่างๆ โดยการเพิ่มหรือลบ css class เข้าไป 
ตัวอย่างต่อไปนี้ เราจะมาดูวิธีการใช้งาน ngClass ในการเพิ่มหรือลบ css class หลายๆตัวพร้อมกัน
 
 

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

@Component({
  selector: 'my-app',
  template: `
  <button class="btn" [ngClass]="allmyclass" 
  (click)="setAllmyClass()">Use ngClass</button>
  `,
})
export class AppComponent  { 

  allmyclass = {}; // กำหนด object ของชื่อ css class
  clickCount = 0;

  // เมื่อคลิกที่ปุ่ม ให้มาทำคำสั่งนี้
  setAllmyClass(){
    // นับค่าจำนวนคลิก
    if(this.clickCount == 3){// ถ้าคลิกครบ 3 ครั้งให้รีเซ็ตค่า
      this.clickCount = 0;     
    }
    this.clickCount++; // บวกค่า
    // เพิ่มหรือลบ css class แต่ละตัวตามเงื่อนไข
    this.allmyclass = {
      'btn-success':this.clickCount==1,
      'btn-danger':this.clickCount==2,
      'btn-info':this.clickCount==3
    }
  }

}
 
พิจารณาในส่วนของ template 
 
  <button class="btn" [ngClass]="allmyclass" 
  (click)="setAllmyClass()">Use ngClass</button>
 
เราใช้ class="btn" กำหนด css class เริ่มต้นของปุ่ม เป็นวิธีการกำหนด css class ปกติ
จากนั้นใช้ 
 
[ngClass]="allmyclass" 
 
ในการกำหนด property ให้กับ ngClass directive ให้มีค่าเท่ากับ allmyclass object ของ css class ที่เรา
กำหนดใน component 
รูปแบบการกำหนด css class object คือ
 
obj = {
  'ชื่อ css class 1':expression 1,
  'ชื่อ css class 2':expression 2,
  'ชื่อ css class 3':expression 3,
  'ชื่อ css class n':expression n
}
 
โดยค่าของ expression จะเป็นค่า true หรือ false โดยถ้าเป็นค่า true ให้ใช้งาน css class นั้น
ถ้า false ให้นำ css class นั้นออก หรือไม่ใช่งาน css class นั้น
 
อย่างในตัวอย่างของเราคือ
 
this.allmyclass = {
  'btn-success':this.clickCount==1,
  'btn-danger':this.clickCount==2,
  'btn-info':this.clickCount==3
}
 
จากรูปแบบการทำงาน ถ้าเรากดปุ่มครั้งแรก ค่า clickCount จะเท่ากับ 1 
css class ที่ชื่อ "btn-success" ก็จะถูกเพิ่มเข้าไปในปุ่ม
ถ้ากดอีกครั้ง ค่า clickCount ก็จะเพิ่ม เป็น 2  
css class ที่ชื่อ "btn-danger" ก็จะถูกเพิ่มเข้าไปในปุ่ม พร้อมกับทำการลบ css class ที่ชื่อ "btn-success"
ออกจากปุ่มด้วย  ในลักษณะการทำงานแบบนี้เป็นต้น
 
สำหรับชื่อของ css class ถ้าเป็นชื่อ พยางค์เดียว เราสามารถละเครื่องหมาย (') qoute) ออกได้ เช่น
 
this.allmyclass = {
  success:this.clickCount==1,
  danger:this.clickCount==2,
  info:this.clickCount==3
}
 
 

การใช้งาน NgStyle

 
เราสามารถกำหนดค่า style property แบบ inline style หลายๆ ค่าพร้อมกันโดยใช้ ngStyle
ตัวอย่างต่อไปนี้ เราจะมาดูวิธีการใช้งาน ngStyle ในการเพิ่มหรือลบ style property หลายๆ ค่า พร้อมกัน
 
 


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

@Component({
  selector: 'my-app',
  template: `
  <button class="btn" (click)="setAllmyStyle()">Use ngStyle</button>
  <div [ngStyle]="allmystyle">This is use ngStyle</div>
  `,
})
export class AppComponent  { 

  allmystyle = {}; // กำหนด object ของชื่อ css class
  clickCount = 0;

  // เมื่อคลิกที่ปุ่ม ให้มาทำคำสั่งนี้
  setAllmyStyle(){
    // นับค่าจำนวนคลิก
    if(this.clickCount == 3){// ถ้าคลิกครบ 3 ครั้งให้รีเซ็ตค่า
      this.clickCount = 0;     
    }
    this.clickCount++; // บวกค่า
    // เพิ่มหรือลบ style property แต่ละตัวตามเงื่อนไข
    this.allmystyle = {
      'color':(this.clickCount==1)?'red':'blue',
      'font-size.px':(this.clickCount==2)?20:12,
      'background-color':(this.clickCount==3)?'yellow':'#EAEAEA'
    }
  }

}
 
การกำหนดค่าให้กับ ngStyle จะคล้ายๆ กับรูปแบบการกำหนดค่าให้กับ ngClass คือเป็นรูปแบบ object
ลักษณะดังนี้
 
รูปแบบการกำหนด style property object คือ
 
obj = {
  'ชื่อ style property 1':expression 1,
  'ชื่อ style property 2':expression 2,
  'ชื่อ style property 3':expression 3,
  'ชื่อ style property n':expression n
}
 
การทำงานของโค้ดตัวอย่างด้านบน คือ เราให้ปุ่มทำคำสั่ง allmystyle() เมื่อมีการคลิก
โดยทำการเพิ่มค่าของ clickCount จากนั้นเรากำหนดให้ค่า style property แต่ละตัว
มีค่าเป็นไปตาม expression หรือนิพจน์ที่เราต้องการ อย่างเช่นเงื่อนไขของ
style property แรกคือ การกำหนดสี color ให้มีค่าเป็นสีแดง เมื่อ clickCount มีค่าเท่ากับ 1 แบบนี้เป็นต้น
 
 
สำหรับการใช้งาน NgModel นั้น เป็น attribute directive ของ FormModule 
เเราสามารถดูรายละเอียดได้ที่บทความนี้
 
การใช้งาน Form กับ การเชื่อมข้อมูลแบบสองทาง ใน Angular เบื้องต้น 
 



การใช้งาน Built-in structural directives


Structural directive หรือ Directive โครงสร้าง เป็นตัวที่ทำหน้าที่ในการกำหนดโครงร่าง layout ของ HTML 
ทำการกำหนดหน้าตาหรือเปลี่ยนแปลงหน้าตาโครงสร้างของ DOM  โดยทั่วไปที่พบเห็นบ่อยๆ ก็คือใช้สำหรับ
ทำการเพิ่ม ลบ หรือจัดการ element ต่างๆ ที่มีการนำ structural directive นี้มาใช้งาน
 
ในส่วนของหัวข้อนี้เราจะได้แนะนำการใช้ structural directive ที่พบเห็นบ่อยทั่วไป คือ
 
  • NgIf ใช้สำหรับกำหนดเงื่อนไขในการเพิ่ม หรือลบ element ออกจาก DOM
  • NgFor ใช้สำหรับวนลูปทำซ้ำเพื่อแสดงรายการใน template
  • NgSwitch ใช้สำหรับปรับเปลี่ยนการแสดงของ directive 
 
 
 

การใช้งาน NgIf

เราสามารถทำการเพิ่ม หรือ ลบ element ต่างๆ ออกจาก DOM โดยการกำหนดด้วย NgIf directive ให้กับ 
element นั้นๆ (หรือเราจะเรียก element ที่มีการใช้งานนี้ว่า host element)  โดยการเชื่อมโยง directive
กับ เงื่อนไขของนิพจน์ที่ต้องการ ยกตัวอย่างเช่น

 

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

@Component({
  selector: 'my-app',
  template: `
  <button class="btn" (click)="setShow()">Test NgIF</button>
  <div *ngIf="isShow">This is use ngIf</div>
  `,
})
export class AppComponent  { 
  // กำหนดค่าเริ่มต้นให้ property isShow มีค่าเป็น false
  isShow:boolean = false;

  // คำสั่งทำงาน เปลี่ยนค่า isShow สลับไปมา ระหว่าง true กับ false
  setShow(){
    if(this.isShow == true){
      this.isShow = false; 
    }else{
      this.isShow = true;
    }
  }

}
 
 
สังเกตที่ส่วนกำหนด template เรามีการใช้ NgIf directive โดยกำหนดไปใน div โดยให้
ngIf มีค่าเท่ากับ isShow มีค่าเป็น true หรือ false โดยถ้ามีค่าเป็น true จะทำให้ div element
ถูกนำมาแสดงเพิ่มเข้ามาใน DOM และถ้า isShow มีค่าเป็น false แล้ว div element นั้นก็จะถูก
ลบหรือนำออกไปจาก DOM ซึ่งต่างจากการซ่อนหรือการแสดง เพราะการซ่อนหรือการแสดง
อย่างเช่นการใช้ class binding 
 
<div [class.hidden]="!isShow">Show with class</div>
 
ก่อนซ่อนหรือแสดงนั้น ตัว element รวมถึง child element ด้านใน จะยังอยู่ใน DOM เพียงแค่ไม่แสดง
ให้เห็นผ่านบราวเซอร์เท่านั้น หรือเราสามารถเช็คหรือตรวจสอบได้ผ่าน dev tools ใน chrome ผ่าน tab
element เลือกเปรียบเทียบดู
 
  <div *ngIf="isShow">This is use NgIf</div>
  <div [class.hidden]="!isShow">Show with class</div>
 
แล้วดูผลลัพธ์ผ่าน dev tool ของ chrome จะเป็นดังรูป
 


 
 
จะพบว่า div ที่มีการใช้งาน NgIf จะไม่ปรากฎใน DOM แต่ div ที่ใช้ class hidden จะยังปรากฏ
อยู่ใน DOM ถึงแม้จะไม่แสดงผลออกมาให้เราเห็นก็ตาม ทีนี้เราลองเปลี่ยนค่า isShow เป็น true
กัน แล้วดูผลลัพธ์  
 


 
 
สังเกตว่า div ที่ใช้ ngIf ปรากฏเข้าเข้ามาใน DOM ดังรูป 
 
เราได้เห็นรูปแบบการใช้งาน NgIf ในการกำหนดการแสดงของ component ในบทความก่อนๆ มาบ้างแล้ว
 
"ทบทวนบทความได้ที่"
การใช้งาน provider ที่ไม่ใช่ service class ใน Angular 
 
การทำงานของ NgIf กรณีลบ component หรือ element จะเหมือนเป็นการคืนค่าทรัพยากรณ์ที่ใช้ในการจัดการ
component นั้นๆ กลับมาด้วย เพราะเมื่อมีการทำลายค่าของ component นั้นรวมถึง component ลูกในลำดับขั้น
ด้านใน ทำให้เราไม่สิ้นเปลืองความจำไปกับสิ่งที่ไม่ได้ใช้งานหรือมองไม่เห็น เท่ากับเป็นการเพิ่มประสิทธิภาพการ
ทำงานโดยรวมของ App ของเราไปด้วย อย่างไรก็ตาม การซ่อนหรือแสดงแบบใช้ class หรือ style ก็ใช่ว่าจะไม่จำเป็น
การซอนหรือแสดงในรูปแบบการใช้ class หรือ style เหมาะสำหรับ element ที่มี element ลูกไม่มาก
    กรณีให้ค่า ngIf มีค่าเท่ากับ null ผลที่ได้คือ ไม่มีการ element นั้นๆ เข้ามาใน DOM ผลลัพธ์เหมือนกับมีค่าเป็น
false 
 
    รูปแบบการใช้ NgIf ข้างต้น เราพบว่า ทำไมถึงต้องมี (*) นำหน้าทุกครั้งกรณีใช้งาน ngIf ทั้งนี้ ก็เพราะว่า
Angular จะทำการย้าย *ngIf="..." เข้าไปไว้ใน template attribute ของ element นั้น ในรูปแบบดังนี้
สมมติเช่น
 
<div *ngIf="isShow">This is use NgIf</div>
 
แปลงครั้งที่ 1 ย้าย *ngIf="..." เข้าไปไว้ใน template attribute จะได้เป็น
 
<div template="ngIf isShow">This is use NgIf</div>
 
แปลงครั้งที่ 2 ย้ายเอา template attribute มาเป็น template element แล้วเอาไปคลุม element 
ที่ใช้งานนั้นอีกที ตามรูปแบบนี้
 
<template [ngIf]="isShow">
<div>This is use NgIf</div>
</template>
 
จะเห็นว่า *ngIf directive จะย้ายมาอยู่ใน <template> element ในรูปแบบการเชื่อมโยงด้วย property [ngIf]
<div> ส่วนที่เหลือ รวมถึง ถ้ามี class หรือ attribute อื่นๆ อยู่ก่อนหน้าแล้ว ทั้งหมดจะถูกย้ายไปไว้ใน <template>
element   แต่ <template> element นั้นจะไม่ถูกนำมาใช้ใน DOM หรือแสดงในหน้าเพจด้วย โดยในหน้าเพจ
จะแสดงเฉพาะผลลัพธ์สุดท้ายเท่านั้นเข้าไปใน DOM  หรือก็คือแสดง
 
<div>This is use NgIf</div>
<!-- มีเฉพาะ <div> element เข้ามาใน DOM เท่านั้น --> 
 
 
 

การใช้งาน NgFor

NgFor คือตัวที่ใช้สำหรับวนลูปแสดง directive ซ้ำ เป็นวิธีการที่ใช้สำหรับแสงลิสต์รายการ ยกตัวอย่างเช่นเราสร้าง
ลิสต์รายการด้วย <ul><li> แล้วเราบอกกับ Angular ว่าเราต้องการใช้ <li> เป็น template สำหรับแสดง
รายการแต่ละรายการในลิสต์ ดูตัวอย่างต่อไปนี้ประกอบ
 


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

@Component({
  selector: 'my-app',
  template: `
  <ul>
    <li *ngFor="let day of Days">
      {{day}}
    </li>
  </ul>
  `,
})
export class AppComponent  { 
  
  Days:string[];

  constructor(){
    this.Days = ["Monday","Tuesday","Wednesday","Thursday","Friday"];
  }

}
 
Angular จะนำค่าตัวแปร Days ที่ตัวแปร Array String ของวันธรรมดา จันทร์ถึงศุกร์ มาวนลูปแสดงใน <li>
โดยค่าที่กำหนดในเครื่องหมายคำพูด ที่กำหนดให้กับ *ngFor นั้น จะไม่ใช่นิพจน์ของ template อย่างที่เราเข้าใจ
แต่ในส่วนนี้จะเรียกว่า microsyntax  หรือภาษาไวยากรณ์ของ Angular ที่กำหนดขึ้นมาและแปลงค่าใช้งานเอง
โดยข้อความ "let day of Days" หมายถึง
 
นำค่าวันที่ใน Array ที่ชื่อ Days วนลูปแต่ละค่ามาเก็บไว้ในตัวแปร local ที่ชื่อ day แล้วนำไปใช้งานใน template
ในแต่ละการทำงานลูปแต่ละครั้ง ตัวแปร day คือตัวแปร input template หรือที่เรารู้จักในชื่อ template input variable 
{{day}} ตัวแปร day นี้คือตัวแปร input template
 
รูปแบบการใช้งาน ngFor ข้างต้นมีการใช้ * นำหน้า การทำงานของมันก็คล้ายๆ กับกรณี ngIf 
 
<li *ngFor="let day of Days">
  {{day}}
</li>
 
แปลงครั้งที่ 1 ย้าย *ngFor="..." เข้าไปไว้ใน template attribute จะได้เป็น
 
<li template="ngFor let day of Days">
  {{day}}
</li>
 
แปลงครั้งที่ 2 ย้ายเอา template attribute มาเป็น template element แล้วเอาไปคลุม element 
ที่ใช้งานนั้นอีกที ตามรูปแบบนี้
 
<template ngFor let-day [ngForOf]="Days">
<li>{{day}}</li>
</template>
 
 
เราลองมาปรับโค้ดตัวอย่างของเราให้ซับซ้อนขึ้นแล้วดูการทำงานเพิ่มเติมกัน
 
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
  <button (click)="addData()">Add Data</button>
  <button (click)="resetData()">Reset Data</button>
  <ul>
    <li (click)="delData(i)"  *ngFor="let staff of staffs;let i=index;let odd=odd;">
      {{i+1}}.{{staff.name}} {{staff.id}} - {{i}} {{odd}}
    </li>
  </ul>    
  <ul>
    <li (click)="delData(i)"  *ngFor="let staff of staffs;let i=index;let odd=odd;trackBy:trackById">
      {{i+1}}.{{staff.name}} {{staff.id}} - {{i}} {{odd}}
    </li>
  </ul>  
  `,
})
export class AppComponent  { 
  
  staffs:Staff[];

  constructor(){
    this.staffs = [
      new Staff(1,'John'),
      new Staff(2,'Linda'),
      new Staff(3,'Manop'),
    ];
  }

  trackById(index: number, item: Staff): number{ 
    return item.id;
  }
  addData(){
    this.staffs.push(
      new Staff(4,'Jubjang')
    )
  }
  delData(id:number){
    this.staffs.splice(id,1);
  }
  resetData(){
    this.staffs = [
      new Staff(7,'John'),
      new Staff(5,'Linda'),
      new Staff(6,'Manop'),
    ];
  }

}


export class Staff{
  constructor(
    public id:number,
    public name:string
  ){}
}
 
ใน template เราจะมีตัวอย่างการใช้งาน ngFor แตกต่างกันสองรุปแบบ
แบบที่สองมีการใช้งาน trackBy ความสำคัญของมันนั้นคืออะไร เราจะได้อธิบายต่อไป
แต่ก่อนอื่น เรามาดูการแปลงค่าของ Angular กันก่อน เอาส่วนของ ngFor ตัวที่สองมาเป็นแนวทาง
 
<li (click)="delData(i)"  *ngFor="let staff of staffs;let i=index;let odd=odd;trackBy:trackById">
  {{i+1}}.{{staff.name}} {{staff.id}} - {{i}} {{odd}}
</li>
 
แปลงครั้งที่ 1 ย้าย *ngFor="..." เข้าไปไว้ใน template attribute จะได้เป็น
 
<li (click)="delData(i)"  template="ngFor let staff of staffs;let i=index;let odd=odd;trackBy:trackById">
  {{i+1}}.{{staff.name}} {{staff.id}} - {{i}} {{odd}}
</li>
 
แปลงครั้งที่ 2 ย้ายเอา template attribute มาเป็น template element แล้วเอาไปคลุม element 
ที่ใช้งานนั้นอีกที ตามรูปแบบนี้
 
<template ngFor let-staff [ngForOf]="staffs" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
    <li (click)="delData(i)">
      {{i+1}}.{{staff.name}} {{staff.id}} - {{i}} {{odd}}
    </li>
</template>
 
และผลลัพธ์สุดท้าย <template> element จะไม่ถูกนำออกไปแสดง และสังเกตว่า รายการใดๆ ที่ไม่ได้อยู่ภายใน 
ngFor="..." ค่าของมันจะถูกย้ายไปไว้ใน element ตั้งต้น อย่าง (click)="delData(i)" ถูกย้ายมาผูกไว้กับ 
<li> element เป็นต้น
    จากรูปแบบการแปลงครั้งที่สอง Angular ใช้คำว่า let ในการประกาศตัวแปร template input variable ที่อ้างอิงใช้
งานเฉพาะ template ใน <li> scope เท่านั้น ไม่สามารถอ้างอิงค่าตัวแปรภายนอก <li> ลูปได้ ในตัวอย่าง
ตัวแปร template input variable ได้แก่ "staff","i","odd" ตัวแปลงค่าทำการแปลง let staff , let i และ let odd
ให้อยู่ในแปรชื่อ let-staff , let-i  และ let-odd
    เปลี่ยนคำว่ "of" กับ "trackby" เป็น "Of" และ "TrackBy" และใช้คำนำหน้าจาก (ngFor) ซึ่งเป็น attribute directive
รวมกันกลายมาเป็น "ngForOf" และ "ngForTrackBy" ตามลำดับ ทั้งสองค่านี้ เป็น input property ของ "ngFor" 
ทำให้รู้ว่า เป็นรายการลิสต์ของตัวแปร "staffs" และคอยติดตามการแสดงค่าผ่านฟังก์ชั่น "trackById" ซึ่งเป็นคำสั่ง
ที่เรากำหนดใน component ตามโค้ดแบบเต็มด้านบน
    ngFor จะทำหน้าที่วนลูปแสดงรายการโดยมี object ที่มี property ค่าต่างๆ เช่น index , odd เป็นต้น นำเข้ามาใช้
งานในลูป จะเห็นว่า ค่า property ของ ngFor อย่าง index และ odd ถูกนำมากำหนดเป็นค่าของตัวแปร let-staff,
let-i และ let-odd ตามรูปแบบ let-i="index" , let-odd="odd" ส่วน let-staff นั้นไม่มีการกำหนดค่าแบบชัดเจน
แต่ค่าของมันก็คือ object รายการใน staffs แต่ละรายการนั่นเอง
 
เรามาดู property ต่างๆ ของ ngFor ถ้าเราสามารถนำค่าไปใช้งานเพิ่มเติมได้ ได้แก่
  • index - เสมือนเป็น key ของ Array ค่าเริ่มต้นที่ 0 วนลูปเพิ่มค่าไปเรื่อยๆ 
  • first - ให้ค่าเป็น true หรือ false ใช้บ่งชี้ว่า รายการนั้นๆในลูปเป็นรายการแรกหรือไม่
  • last - ให้ค่าเป็น true หรือ false ใช้บ่งชี้ว่า รายการนั้นๆในลูปเป็นรายการสุดท้ายหรือไม่
  • even - ให้ค่าเป็น true หรือ false ใช้บ่งชี้ว่า รายการนั้นๆในลูปเป็นรายการลำดับเลขคู่หรือไม่
  • odd - ให้ค่าเป็น true หรือ false ใช้บ่งชี้ว่า รายการนั้นๆในลูปเป็นรายการลำดับเลขคี่หรือไม่
 
รายการข้างต้น เป็น property ของ ngFor เรียกอีกอย่างว่าตัวแปร local ในตัวอย่างโค้ดของเรา
มีการนำ index และ odd มาใช้งาน
 

ตัวแปร Template input variable

จากตัวอย่างเราได้เห็นตัวแปร "staff" "i" และ "odd" ที่เราประกาศด้วยการใช้งาน let ตัวแปรเหล่านี้เราเรียก
ว่า template input variable เป็นตัวแปรที่ใช้อ้างอิงใน template ที่ถูกสร้างขึ้น แต่ละอัน ตามรูปแบบการ
แปลงค่าตามที่เราอธิบายไป
 
ตัวแปร template input variable นั้นเป็นคนละตัวกับตัวแปร template reference variable 
 
เราประกาศใช้ตัวแปร template input variable โดยใช้ let อย่าง let staff ตัวแปร staff นั้นจะถูกจำกัดการใช้งาน
เฉพาะใน template ที่วนลูปแสดงแต่ละรายการเท่านั้น เราสามารถใช้ชื่อตัวแปร staff ซ้ำกับชื่อ ภายนอก
structural directive อื่นๆ ได้ โดยจะเป็นคนละตัวกัน
 
ส่วนตัวแปร template reference variable เราประกาศด้วยใช้ (#) นำหน้า ในรูปแบบ เช่น (#var) ตัวแปรนี้จะอ้าง
อิงค่จากรายการ element ที่ได้กำหนดค่านั้นๆ ไว้ และสามารถใช้งานในทุกๆ ที่ใน template ทั้งหมด
 
ดังนั้นตัวแปร #staff กับ let staff จึงเป็นคนละตัวแปรกัน
 
"ทบทวนตัวแปร template reference variable ได้ที่"
การรับค่า input จาก user ใน Angular App เบื้องต้น 
 

การใช้งาน *ngFor รวมกับ trackBy

จากตัวอย่างโค้ดด้านบน ที่เรามีการแสดงการใช้งาน ngFor แบบที่มี trackBy และไม่มี trackBy property
ทั้งนี้ก็ด้วยเหตุผลที่ว่า การใช้งาน ngFor กรณีที่ข้อมูลมีปริมาณมากๆ จะส่งผลต่อการแสดงผลที่จะทำงานช้า
ยิ่งถ้าเป็นการเปลี่ยนแปลงข้อมูลเพียงเล็กน้อย อย่างการเปลี่ยนแปลงโดยการลบหรือการเพิ่มรายการเพียง
รายการเดียว กลับมีผลกับรายการที่เหลือทั้งหมด ดังนั้นการใช้งาน trackBy จะช่วยแก้ปํญหากรณีดังกล่าว
ข้างต้นได้
 
ผลที่ได้ก็คือ กรณีไม่ใช้งาน trackBy แล้วถ้าเกิดมีการ รีเซ็ตค่าหรือดึงข้อมูลเดิมมาแสดง กลายเป็นเป็นการ
ลบ DOM รายการเก่าทั้งหมด แล้วแทนที่ด้วย DOM รายการใหม่เข้ามาแทน แต่ถ้าใช้การกำหนด trackBy 
การรีเซ็ตค่าหรือการแสดงค่าเดิม DOM จะไม่ถูกลบและแทนที่ใหม่ การเปลี่ยนแปลงของ DOM จะเปลี่ยน
และแทนที่เฉพาะรายการที่มีการเปลี่ยนแปลงเท่านั้น ดังนั้นจีงมีประโยชน์ในกรณีลิสต์รายการมีจำนวนมากๆ
ทำให้การแสดงผลเป็นไปอย่างมีประสิทธิภาพมากขึ้น 
 
อย่างในโค้ดตัวอย่าง เราใช้งาน ค่า trackBy จาก ฟังก์ชั่น trackById
 
trackById(index: number, item: Staff): number{ 
	return item.id;
}
 
จากโค้ด ใชค่า id property ของ staff object เป็นค่าที่ได้จากฟังกืชั่น trackById 
 

 

การใช้งาน NgSwitch

NgSwitch จะคล้ายกับคำสั่ง switch ใน JavaScript โดยสามารถที่จะแสดง element หนึ่งๆ จากรายการ
element อื่นๆ ตามเงื่อนไข โดย Angular จะทำการเพิ่ม เพราะ element ที่ถูกเลือกเท่านั้นเข้าไปใน DOM
 
ในการใช้งาน NgSwitch จะมี directive ที่เกี่ยวข้องเพิ่มเติมดังนี้ คือ ngSwitch, ngSwitchCase และ 
ngSwitchDefault ตามตัวอย่างด้านล่าง

 

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

@Component({
  selector: 'my-app',
  template: `
  <input name="gender" type="radio" (click)="gender='male'" /> Male 
  <input name="gender" type="radio" (click)="gender='female'"  /> Female 
  <ul [ngSwitch]="gender">
    <li *ngSwitchCase="'male'" >I'm male</li>
    <li *ngSwitchCase="'female'" >I'm female</li>
    <li *ngSwitchDefault >Not specify</li>
  </ul>
  `,
})
export class AppComponent  { 
  
  gender:string;


}
 
ตัวอย่างข้างต้น เราใช้วิธีกำหนดให้เมื่อคลิกที่ input radio ที่เป็น ตัวเลือกระบุเพศ ว่า
เป็น male หรือ female ให้ค่าตัวแปร gender มีค่าตามคำสั่งการทำงานที่กำหนด
ถ้าคลิกที่ male ให้ gender มีค่าเป็น male ถ้ากด female ให้ gender มีค่าเป็น female
แต่ค่าเริ่มต้นเราไม่ได้กำหนด ค่าจึงเป็น undefined
    จากตัวอย่างโค้ดเราจะเห็นว่า ngSwitch ไม่มีการกำหนด (*) ทั้งนี้ก็เพราะ ngSwitch ตัวของมันเอง
นั้นเป็นเพียง attribute directive ไม่ได้เป็น structural directive จึงไม่มีการแปลงค่า เหมือน
กับ ngIf และ ngFor 
     แต่อย่างไรก็ตามก็มี directive ที่เกี่ยวข้องมีการกำหนด (") เนื่องจากเป็น structural directive
ทำการแปลงค่าในลักษณะดังนี้
 
<ul [ngSwitch]="gender">
<li *ngSwitchCase="'male'" >I'm male</li>
<li *ngSwitchCase="'female'" >I'm female</li>
<li *ngSwitchDefault >Not specify</li>
</ul>
 
แปลงครั้งที่ 1 ย้าย *ngSwitchCase="..." และ *ngSwitchDefault เข้าไปไว้ใน template attribute จะได้เป็น
 
<ul [ngSwitch]="gender">
<li template="ngSwitchCase 'male'" >I'm male</li>
<li template="ngSwitchCase 'female'" >I'm female</li>
<li template="ngSwitchDefault">Not specify</li>
</ul>
 
แปลงครั้งที่ 2 ย้ายเอา template attribute มาเป็น template element แล้วเอาไปคลุม element 
ที่ใช้งานนั้นอีกที ตามรูปแบบนี้
 
<ul [ngSwitch]="gender">
<template [ngSwitchCase]="'male'">
<li>I'm male</li>
</template>
<template [ngSwitchCase]="'fmale'">
<li>I'm female</li>
</template>
<template ngSwitchDefault>
<li>Not specify</li>
</template>
</ul>
 
สังเกตว่า ngSwitchDefault ไม่มีการกำหนดค่า จึงไม่มีการใช้ [] เช่นเดียวกับกรณี ngFor จากหัวข้อ
ที่ผ่านมา
    เมื่อเริ่มต้น <li> element ตัวสุดท้ายจะถูเพิ่มเข้ามาใน DOM เพียงตัวเดียว เนื่องจากเป็นค้าเริ่มต้น
กรณีเงื่อนไขตัวแปร gender ไม่ตรงกับเงื่อนไขอื่นใด และเมื่อเราคลิกเลือก male เรายการ
<li> ลิสต์รายการแรกก็จะถูกเพิ่มเข้ามาใน DOM แทน พร้อมทั้งลบ <li> element ที่แสดงก่อนหน้า
ออกไปด้วย
 
 
ตอนนี้เราได้รู้จักกับ build-in direcitve ที่ใช้งานบ่อยใน Angular เพิ่มขึ้น เนื้อหาตอนหน้าเราจะมาดูต่อ
เกี่ยวกับ template referenc variable ทีเรามีการกล่าวไปแล้วในบทความตอนนี้ รวมถึงจะไปดูเกี่ยวกับ
การใช้งาน Input and output properties (@Input และ @Output) รอติดตาม น่าจะเป็นตอนสุดท้าย
ที่เกี่ยวกับการใช้งาน template syntax เบื้องต้น

 


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ









เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง











เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ