เนื้อหานี้เราจะมาพูดถึงการใช้งาน template syntax หรือรูปแบบการเขียนโค้ดใน Angular
ที่ใช้สำหรับแสดงข้อมูล และการรับค่า event จากผู้ใช้ ซึ่งจะมีประโยชน์มากสำหรับการใช้งาน
การเชื่อมโยงข้อมูลระหว่างแหล่งข้อมูล และหน้าแสดงผล หรือที่เราได้เจอบ่อยๆ ที่ผ่านมา
ก็คือ การเชื่อมโยงข้อมูลระหว่าง Component Property กับ Template View
การใช้งาน HTML ใน Template
รูปแบบภาษา HTML ส่วนใหญ่แล้วจะรองรับการใช้งานใน Angular template ยกเว้น <script> tag
ที่ไม่สามารถใช้งานได้ เหตุผลในด้านความปลอดภัย ป้องกันความเสี่ยงจากการโจมตีของคำสั่งใน script
นอกจากนั้นยังมีบาง tag ที่อาจจะไม่สมเหตุสมผลหากนำมาใช้งานใน template อย่างเช่น <html>
<body> <base> ทั้งนี้ก็อย่างที่ทราบกันว่า Angular App จะเป็นลักษณะ Single Page App ซึ่ง tag ที่
กล่าวมาข้างต้น จะถูกโหลดหรือเรียกใช้งานครั้งแรกเพียงครั้งเดียวไปแล้ว จึงไม่นิยมนำมาใช้ใน template
ไม่เพียง HTML tag ที่เราสามารถนำมาใช้งาน template แต่เรายังสามารถกำหนด tag เฉพาะขึ้นมาเองหรือ
ที่เรียกว่า customer tag ด้วยการใช้งาน Component และ Directive ซึ่งจะหมายถึงการสร้าง element และ
attribute ใหม่ขึ้นมา ลำดับต่อไปนี้ เราจะได้รู้จักวิธีการใช้งานอ่านค่าและการตั้งค่า DOM (Document Object
Model) แบบอัตโนมัติ ผ่านวิธีการเชื่อมโยงข้อมูลแบบต่างๆ
การแทรกค่าตัวแปร Interpolation ( {{...}} )
รูปแบบการแทรกค่าตัวแปร เป็นรูปแบบการเชื่ยมโยงข้อมูลระหว่าง Component กับ Template ที่เรา
พบบ่อยในตัวอย่าง ที่ผ่านๆ มา
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Hello {{name}}</h1> `, }) export class AppComponent { name = 'Angular'; }
การแทรกค่าตัวแปร โดยการกำหนดตัวแปรไว้ใน วงเล็บปีกกาเปิดปิดสองอัน {{...}} ตามตัวอย่างด้านบน
เป็นการใช้ค่าจาก component มาแสดงใน template
แต่โดยทั่วไปส่วนมากแล้ว ข้อความที่อยู่ในวงเล็บปีกกาจะเป็นข้อความบรรยายนิพจน์ หรือ template expression
ยกตัวอย่างเช่น "x มีค่าเป็นจริง" , "x มีค่าเป็นเท็จ" , "ถ้า a เป็น จริง ให้ a=1 ถ้าไม่ใช่แล้วให้ a=5" เหล่านี้เป็นต้น
ซึ่ง Angular จะทำการประมวลผลนิพจน์แล้วเปลี่ยนเป็นข้อความ String ตัวอย่างโค้ดด้านล่างเป็นนิพจน์
การบวกค่าของตัวเลข 2 ตัว ที่มีการแทรกค่า
<!-- "ผลลัพธ์ของ 1 + 1 คือ 2" --> <p>The sum of 1 + 1 is {{1 + 1}}</p>
ข้อความ 1+1 คือนิพจน์ หรือ template expression ผลลัพธ์ที่ได้คือจะได้ค่าในส่วนของการแทรกค่าเท่ากับ 2
สมมติเราเปลี่ยน
<!-- "ผลลัพธ์ของ NaN" --> <p>{{1 + a}}</p>
a เป็น null คือไม่มีค่า ผลการประมวลผลของ Angular จะได้การแทรกค่าเท่ากับข้อความ "NaN"
เรามาดูเกี่ยวกับ Template expressions ในข้อถัดไปกันเพิ่มเติม
ทำความรู้จักกับ Template expressions
Angular จะทำการประมวลค่าของนิพจน์ (template expression) แล้วนำค่าที่ได้ไปกำหนดไว้ใน
property เป้าหมายที่มีการเชื่อมโยง ซึ่งอาจจะเป็น HTML element, Component หรือ Directive
การแทรกค่าในรูปแบบ {{1 + 1}} ในตัวอย่าง มีรูปแบบมาจากการเชือมโยงแบบ property binding ซึ่งเราจะได้
ทำความรู้จักในหัวข้อต่อๆ ไป ซึ่งค่านิพจน์อยู่ภายในเครื่องหมายคำพูด ทางขวาเมือของเครื่องหมาย =
ตามรูปแบบ [property]="expression" ยกตัวอย่างเช่น
<div>{{1 + 1}}</div>
ก็มาจาก
<div [innerHTML]="1+1"></div>
innerHTML เป็น DOM property ของ <div> 1+1 ในเครื่องหมายคำพูด "..." เป็นนิพจน์
ถึงแม้ว่านิพจน์ใน JavaScript จำนวนมากจะสามารถใช้ใน template expression ได้ แต่ก็มีบางรูปแบบ
ที่มีผลข้างเคียง และถูกห้ามนำมาใช้งาน ในการกำหนดนิพจน์ใน Template ได้แก่
- การกำหนดค่า (=, +=, -=,....)
- การใช้ new
- การใช้นิพจน์ต่อเนื่องด้วย ; หรือ :
- การเพิ่มค่าและการลดค่าด้วย (++ และ --)
ข้อแตกต่างเด่นชัดจาก JavaScript คือ
- ไม่รองรับการดำเนินการแบบบิตด้วย | และ &
- มีตัวจัดการนิพจน์ของ template ใหม่เพิ่มเข้ามา เช่น | และ ?.
ข้อความนิพจน์ (Expression context)
โดยปกติทั่วไปนิพจน์จะเป็นค่าตัวแปรอ้างอิง component อย่างโค้ดตัวอย่างด้านล่างต่อไปนี้
title ที่อยู่ในวงเล็บปีกกาสองอัน และ isUnchanged ที่อยู่ใน เครื่องหมายคำพูด คือค่าของ
component property
{{title}} <span [hidden]="isUnchanged">changed</span>
นอกจากนั้น นิพจน์ยังอาจอ้างอิงถึง ค่า property ของ template เช่นตัวแปร template input variable
ที่กำหนดด้วย (let staff) หรือ ตัวแปรอ้างอิง template reference variable ที่กำหนด้วย (#staffInput) ดังตัวอย่าง
โค้ดต่อไปนี้
<div *ngFor="let staff of staffs">{{staff.name}}</div> <input #staffInput> {{staffInput.value}}
สำหรับข้อความในเงื่อนไขของนิพจน์จะเป็นการผสมกันระหว่าง template variable ,directive object (ถ้ามี) และ component property
โดยกรณีมีการอ้างอิงชื่อเดียวกันหรือซ้ำกัน ให้พิจารณาว่าตัวแปรนั้นๆ เป็นตัวแปร
โดยกรณีมีการอ้างอิงชื่อเดียวกันหรือซ้ำกัน ให้พิจารณาว่าตัวแปรนั้นๆ เป็นตัวแปร
ใดตามลำดับดังนี้ คือ ให้เป็นตัวแปร template variable , ตัวแปร directive object และ สุดท้ายตัวแปรจาก
component property
อย่างเช่นตัวอย่างจากโค้ดก่อนหน้า
<div *ngFor="let staff of staffs">{{staff.name}}</div>
ใน component มี property ที่ชื่อ staff และใน template มีการใช้ *ngFor กำหนดตัวแปร staff ซึ่งเป็น
template variable ดังนั้น staff ใน {{staff.name}} จึงเป็นการอ้างอิงถึงตัวแปร template input variable
ไม่ใช่ตัวแปรจาก component property
นิพจน์ของ template ไม่สามารถอ้างอิงถึงตัวแปร global อย่าง "window" หรือ "document"
ไม่สามารถเรียกใช้คำสั่ง console.log หรือ Math.max ได้
แนวทางการกำหนดนิพจน์ Expression guidelines
ประกอบด้วยแนวทางดังต่อไปนี้
ต้องไม่เกิดผลกระทบข้างเคียง
นิพจน์ของ template ไม่ควรที่จะทำให้เกิดการเปลี่ยนแปลงใดๆ ในสภาวะของ App เกิดขึ้น ควรเป็นเพียงแค่การ
เปลี่ยนแปลงค่าของ property เป้าหมาย
กฎนี้มีความจำเป็นสำหรับนโยบายของ Angular ที่ระบุว่า "การเคลื่อนไหวของข้อมูลต้องเป็นไปในทิศทางเดียวกัน"
(เช่น ส่งผ่านข้อมูลจากค่าใน component ไปแสดงยัง template)
เราควรจะต้องไม่กังวลเกี่ยวกับการอ่านค่าของ component ที่อาจจะมีการการเปลี่ยนแปลงค่าบางค่าที่แสดงออกมา
การแสดงผลควรมีเสถียรภาพตลอดการส่งผ่านการสร้างการแสดงผลในแต่ละครั้ง
ประมวลผลเร็ว
Angular ประมวลผลนิพจน์ของ template ทุกๆ ครั้งหลังจากมีการตรวจพบการเปลี่ยนแปลง วงจรการตรวจจับ
การเปลี่ยนแปลง ถูกเรียกให้ทำงานในหลายๆ กิจกรรมที่มีลักษณะทำงานตามลำดับเกิดขึ้นไม่พร้อมกัน อย่างเช่น
การรอผลลัพธ์จากการใช้งาน http , การกำหนด event ด้วยการตั้งเวลา , การกดที่แป้นพิมพ์หรือการเคลื่อนเมาส์
นิพจน์ควรจทำงานให้เสร็จอย่างรวดเร็วหรือไม่ เราก็ใช้ประสบการณ์การใช้งานของผู้ใช้มาช่วย
อย่างในกรณ๊เครื่องที่ทำงานช้า อาจจะพิจารณาการนำระบบแคชค่า มาใช้งาน
ความเรียบง่าย
แม้ว่าเราสามารถที่จะเขียนนิพจน์ของ template ในรูปแบบที่ซับซ้อนได้ แต่ก็ควรจะหลีกเลี่ยงรูปแบบที่ซับซ้อน
ควรใช้งานจากค่า property และ method คำสั่งใน component ให้เป็นบรรทัดฐานปกติ การใช้ (!) กำหนดเงื่อนไข
ตรงข้ามเป็นวิธีที่ควรนำมาใช้ ซึ่งการทำนิพจน์ให้อยู่ในรูปแบบที่เรียบง่ายจะทำให้การพัฒนา App เป้นไปอย่างสะดวกง่ายดาย
นิพลหรือฟังก์ชั่นค่าคงที่
นิพจน์ที่เป็นฟังก์ชั่นค่าคงที่หรือฟังก์ชั่นเอกลักษณ์เป็นสิ่งที่ดีเพราะจะไม่มีผลกระทบข้างเคียงใดๆ และยังเพิ่มประสิทธิภาพ
ในการดำเนินการตรวจสอบการเปลี่ยนแปลงค่าใน Angular อีกด้วย
ใน Angular นิพจน์ที่เป็นฟังก์ชั่นค่าคงที่ จะคืนค่าเป็นสิ่งเดียวกันทุกครั้งเสมอ จนกว่าค่าผันแปรจะเปลี่ยนแปลง
ค่าผันแปรไม่ควรเปลี่ยนแปลงระหว่างการวกกลับครั้งเดียวในลูป ถ้านิพจน์คืนค่าเป็น strng หรือ number โดยจะเป็นค่าเดียวกัน
เมื่อมีการเรียกใช้สองครั้ง ถ้านิพจน์มีกาาคืนค่าเป็น object (รวมถึง array) จะคืนค่าเป็น object อ้างอิงเดียวกันเมื่อถูกเรียกใช้สองครั้ง
การใช้งานคำสั่งควบคุม template (Template statements)
คำสั่งควบคุม template รับผิดชอบในการตรวจจับเหตุการณ์ event ที่เกิดขึ้น โดยการเชื่อมโยงกับเป้าหมาย เช่น elelment ,
component หรือ directive เราจะได้เห็นการใช้งาน คำสั่งควบคุม template ในส่วนของ "event binding" หรือ
การเชื่อมโยงด้วย event โดยคำสั่งควบคุม template จะอยู่ในเครื่องหมายคำพูด ทางขวามือของเครื่องหมาย = ตามรูปแบบ (event)="statement"
<button (click)="deleteStaff()">Delete Staff</button>
คำสั่งควบคุม template จะมีผลกระทบ ซึ่งเป็นจุดสำคัญของ event ที่ใช้สำหรับอัพเดทสภาวะของ App
จากการกระทำของ user
การตอบสนองต่อ event เป็นอีกด้านของกฎใน Angular ที่ว่า "การเคลื่อนไหวของข้อมูลต้องเป็นไปในทิศทางเดียวกัน"
(เช่น ส่งผ่านข้อมูลจาก template ไปยัง แหล่งข้อมูลอย่างค่าใน component) เราสามารถ เปลี่ยนแปลงค่าใดๆ โด้อย่างอิสระ ทุกที่ ในขณะที่มีการวนกลับมาเข้า event ลูป
รูปแบบของคำสั่งควบคุม template จะเหมือนกับ นิพจน์ของ template มีลักษณะคล้ายกับ JavaScript โดยคำสั่งควบคุม template มีไวยกรณ์แตกต่างจากนิพจน์ของ template ในเรื่องการสนับสนุนการใช้งานการใช้เครื่องหมายกำหนดค่าด้วย
( = ) หรือการใช้นิพจน์แบบต่อเนื่องด้วย ( ; หรือ , )
ในคำสั่งควบคุม template ไม่อนุญาตให้ใช้งานคำสั่ง JavaScript ดังต่อไปนี้
- new
- ตัวดำเนินการเพิ่มค่าและลดค่าด้วย ( -- และ ++ )
- ตัวดำเนินการกำหนดค่าด้วย ( += และ -= )
- ตัวดำเนินการแบบบิตด้วย | และ &
- ตัวดำเนินการของนิพจน์ template | และ ?.
ข้อความในคำสั่งควบคุม
เช่นเดียวกับนิพจน์ คำสั่งควบคุม สามารถอ้างถึงเฉพาะข้อความคำสั่งควบคุมเท่านั้น ซึ่งก็คือคำสั่งใน component
ที่เชื่อมโยงกับ event
ข้อความคำสั่งควบคุม โดยปกติทั่วไปเป็นค่าตัวแปรอ้างอิง component คำสั่ง deleteStaff ใน
(click)="deleteStaff()" คือ ฟังก์ชั่นคำสั่งหรือ method ใน component
<button (click)="deleteStaff()">Delete Staff</button>
นอกจากนั้นข้อความคำสั่งควบคุม อาจจะยังอ้างอิงถึง property ของ template นั้นได้อีกด้วย อย่างตัวอย่าง
ต่อไปนี้ ตัวแปร "$event" object ,ตัวแปร template input variable (let staff) และตัวแปรอ้างอิง template
reference variable (#staffForm) ทั้งสามตัวแปรนี้ เป็นค่าที่ส่งเข้าไปในคำสั่งของ component
<button (click)="onSave($event)">Save</button> <button *ngFor="let staff of staffs" (click)="deleteStaff(staff)">{{staff.name}}</button> <form #staffForm (ngSubmit)="onSubmit(staffForm)"> ... </form>
ชื่อตัวแปรในข้อความ template จะถูกกำหนดใช้งานก่อนชื่อตัวแปรใน component อย่างในคำสั่ง deleteStaff(staff)
คำว่า "staff" คือตัวแปร template input variable ไม่ใช้ตัวแปร staff ที่เป็น property ของ component
คำสั่งควบคุม template ไม่สามารถอ้างอิงถึงตัวแปร global อย่าง "window" หรือ "document"
ไม่สามารถเรียกใช้คำสั่ง console.log หรือ Math.max ได้
แนวทางการกำหนดคำสั่งควบคุม Statement guidelines
ใช้แนวทางเดียวกับการกำหนดนิพจน์ของ template โดยพยายามหลีกเลี่ยงการเขียนคำสั่งควบคุมที่ซับซ้อน ควรเลือกใช้
การเรียกใช้คำสั่งหรือ การกำหนดค่า property แบบปกติ
ตอนนี้เราได้รู้จักกับนิพจน์ของ template และ คำสั่งควบคุม template ไปบ้างแล้ว ในเนื้อหาตอนหน้า เราจะได้รู้จักวิธีการ
เชื่อมโยงระหว่างข้อมูล ในรูปแบบอื่นๆ ต่อจากรูปแบบการแทรกค่าตัวแปร ที่ได้กล่าวไปแล้ว รอติดตาม