1. ก่อนเริ่มต้น

Angular Signals จะแนะนำ Reactive Primitive 3 รายการให้กับ Angular ที่คุณรู้จักและชื่นชอบ ซึ่งจะช่วยลดความซับซ้อนในการพัฒนาและช่วยให้คุณสร้างแอปได้เร็วขึ้นโดยค่าเริ่มต้น
สิ่งที่คุณจะสร้าง
- คุณได้เรียนรู้เกี่ยวกับ Primitive แบบรีแอกทีฟ 3 รายการที่เปิดตัวพร้อมกับ Angular Signals ได้แก่
signal(),computed()และeffect() - ใช้ Angular Signals เพื่อขับเคลื่อนเกม Angular Cipher การเข้ารหัสคือระบบสำหรับการเข้ารหัสและถอดรหัสข้อมูล ในเกมนี้ ผู้ใช้สามารถถอดรหัสข้อความลับได้โดยการลากและวางคำใบ้เพื่อแก้รหัส ปรับแต่งข้อความ และแชร์ URL เพื่อส่งข้อความลับให้เพื่อน

ข้อกำหนดเบื้องต้น
- ความรู้เกี่ยวกับ Angular และ Typescript
- แนะนำ: ดู Rethinking Reactivity with Signals เพื่อดูข้อมูลเกี่ยวกับไลบรารี Angular Signals
2. รับโค้ด
ทุกอย่างที่คุณต้องการสำหรับโปรเจ็กต์นี้อยู่ใน Stackblitz Stackblitz เป็นวิธีที่แนะนำในการทำตาม Codelab นี้ หรือจะโคลนโค้ดแล้วเปิดในสภาพแวดล้อมการพัฒนาที่คุณชื่นชอบก็ได้
เปิด Stackblitz และเรียกใช้แอป
หากต้องการเริ่มต้นใช้งาน ให้เปิดลิงก์ Stackblitz ในเว็บเบราว์เซอร์ที่คุณชื่นชอบ
- เปิดแท็บใหม่ในเบราว์เซอร์แล้วไปที่ https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcipher%2Fservice.cipher.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts
- Fork Stackblitz เพื่อสร้างพื้นที่ทำงานที่แก้ไขได้ของคุณเอง Stackblitz ควรเรียกใช้แอปโดยอัตโนมัติ และคุณก็พร้อมใช้งาน
ทางเลือกอื่น: โคลนที่เก็บและแสดงแอป
การใช้ VSCode หรือ IDE ในเครื่องเป็นอีกวิธีหนึ่งในการทำตาม Codelab นี้
- เปิดแท็บใหม่ในเบราว์เซอร์แล้วไปที่ https://github.com/angular/codelabs/tree/signals-get-started
- Fork และโคลนที่เก็บ แล้วใช้คำสั่ง
cd codelabs/เพื่อย้ายไปยังที่เก็บ - ตรวจสอบสาขาโค้ดเริ่มต้นด้วยคำสั่ง
git checkout signals-get-started - เปิดโค้ดใน VSCode หรือ IDE ที่ต้องการ
- หากต้องการติดตั้งทรัพยากร Dependency ที่จำเป็นในการเรียกใช้เซิร์ฟเวอร์ ให้ใช้คำสั่ง
npm install - หากต้องการเรียกใช้เซิร์ฟเวอร์ ให้ใช้คำสั่ง
ng serve - เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:4200
3. กำหนดพื้นฐาน
จุดเริ่มต้นของคุณคือเกม Angular Cipher แต่เกมยังไม่ทำงาน Angular Signals จะขับเคลื่อนฟังก์ชันการทำงานของเกม

หากต้องการเริ่มต้น ให้ดูเวอร์ชันที่เสร็จสมบูรณ์ของสิ่งที่คุณจะสร้างที่ Angular Signals Cypher
- ดูข้อความที่เข้ารหัสบนหน้าจอ
- ลากและวางปุ่มตัวอักษรในปุ่มกดเพื่อไขรหัสและถอดรหัสข้อความลับ
- หากทำสำเร็จ ให้ดูว่าข้อความอัปเดตอย่างไรเพื่อถอดรหัสข้อความลับเพิ่มเติม
- คลิกปรับแต่งเพื่อเปลี่ยนผู้ส่งและข้อความ จากนั้นคลิกสร้างและคัดลอก URL เพื่อดูค่าบนหน้าจอและการเปลี่ยนแปลง URL
- เคล็ดลับ: คัดลอกและวาง URL ลงในแท็บใหม่ หรือแชร์กับเพื่อน แล้วดูว่าระบบจัดเก็บผู้ส่งและข้อความใน URL อย่างไร

4. กำหนด signal() แรก
สัญญาณคือค่าที่บอก Angular ได้เมื่อมีการเปลี่ยนแปลง สัญญาณบางอย่างสามารถเปลี่ยนแปลงได้โดยตรง ในขณะที่สัญญาณอื่นๆ จะคำนวณค่าจากค่าของสัญญาณอื่นๆ สัญญาณจะสร้างกราฟแบบมีทิศทางของ Dependency ที่จำลองวิธีที่ข้อมูลไหลในแอป
Angular สามารถใช้การแจ้งเตือนจากสัญญาณเพื่อทราบว่าคอมโพเนนต์ใดที่ต้องตรวจหาการเปลี่ยนแปลง หรือเพื่อเรียกใช้ฟังก์ชัน effect ที่คุณกำหนด
แปลง superSecretMessage เป็น signal()
superSecretMessage คือค่าใน MessageService ที่กำหนดข้อความลับที่ผู้เล่นถอดรหัส ปัจจุบันค่าดังกล่าวไม่ได้แจ้งให้แอปทราบถึงการเปลี่ยนแปลง ปุ่มปรับแต่งจึงใช้งานไม่ได้ คุณแก้ปัญหานี้ได้ด้วยสัญญาณ
การทำให้ superSecretMessage เป็นสัญญาณจะช่วยให้คุณแจ้งส่วนต่างๆ ของแอปที่ต้องทราบเมื่อข้อความมีการเปลี่ยนแปลงได้ เมื่อปรับแต่งข้อความในกล่องโต้ตอบ คุณจะตั้งค่าสัญญาณเพื่ออัปเดตส่วนอื่นๆ ของแอปด้วยข้อความใหม่
หากต้องการกำหนดสัญญาณแรก ให้ทำตามขั้นตอนต่อไปนี้ภายใต้ความคิดเห็น TODO(1): Define your first signal() ในแต่ละไฟล์
- ในไฟล์
service.message.tsให้ใช้ไลบรารี Signals เพื่อทำให้superSecretMessageมีการโต้ตอบ
src/app/secret-message/service.message.ts
superSecretMessage = signal(
'Angular Signals are in developer preview in v16 today!'
);
ซึ่งจะแจ้งให้คุณนําเข้า signal จาก @angular/core โดยอัตโนมัติ หากรีเฟรชหน้าเว็บ คุณอาจพบข้อผิดพลาดในตำแหน่งที่คุณเคยอ้างอิงถึง superSecretMessage เนื่องจากคุณเปลี่ยนประเภท superSecretMessage จาก string เป็น SettableSignal<string> คุณแก้ไขปัญหานี้ได้โดยเปลี่ยนการอ้างอิงทั้งหมดของ superSecretMessage ให้ใช้ Signals API ไม่ว่าคุณจะอ่านค่าที่ใด ให้เรียกใช้ตัวรับสัญญาณ superSecretMessage() และไม่ว่าคุณจะเขียนค่าที่ใด ให้ใช้ .set API ใน SettableSignal เพื่อตั้งค่าใหม่สำหรับข้อความ
- ในไฟล์
secret-message.tsและservice.message.tsให้อัปเดตการอ้างอิงทั้งหมดของsuperSecretMessageเป็นsuperSecretMessage()
src/app/secret-message/secret-message.ts
// Before
this.messages.superSecretMessage
this.messages.superSecretMessage = message;
// After
this.messages.superSecretMessage()
this.messages.superSecretMessage.set(message);
src/app/secret-message/service.message.ts
// Before
this.superSecretMessage
// After
this.superSecretMessage()
ดูสัญญาณอื่นๆ อีก 2 รายการ
- โปรดทราบว่าคุณมีสัญญาณอื่นๆ อีก 2 รายการในแอป ดังนี้
src/app/cipher/service.cipher.ts
cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);
CipherService กำหนดcipherสัญญาณ ซึ่งเป็นการแมปคู่คีย์-ค่าแบบสุ่มของตัวอักษรหนึ่งตัวในตัวอักษรกับcipherตัวอักษรใหม่ คุณใช้พารามิเตอร์นี้เพื่อสลับข้อความและพิจารณาว่าผู้เล่นจะพบการจับคู่ที่สำเร็จบนแป้นพิมพ์หรือไม่
นอกจากนี้ คุณยังมีdecodedCipherสัญญาณของคู่คีย์-ค่าที่ถอดรหัสสำเร็จแล้ว ซึ่งคุณจะเพิ่มเข้าไปเมื่อผู้เล่นแก้ปริศนาได้
คุณสามารถนำการตอบสนองไปใช้ได้ทุกที่ ซึ่งเป็นคุณลักษณะที่ไม่เหมือนใครและทรงพลังของการออกแบบไลบรารีสัญญาณของ Angular คุณกำหนดสัญญาณครั้งเดียวในบริการของแอป และใช้สัญญาณเหล่านั้นในเทมเพลต คอมโพเนนต์ ไปป์ บริการอื่นๆ หรือที่ใดก็ตามที่คุณเขียนโค้ดแอปพลิเคชันได้ โดยไม่ได้จำกัดหรือผูกมัดกับขอบเขตของคอมโพเนนต์
ยืนยันการเปลี่ยนแปลง
- คุณต้องทำอีก 1 ขั้นตอนก่อนที่แอปจะทำงานได้ ในตอนนี้ ให้ลองเพิ่ม
console.log()ในส่วนต่างๆ ของแอปเพื่อดูว่าระบบตั้งค่าsuperSecretMessageใหม่ของคุณอย่างไร

5. กำหนด computed() แรก
ในหลายๆ สถานการณ์ คุณอาจพบว่าตัวเองกำลังดึงข้อมูลสถานะจากค่าที่มีอยู่ การอัปเดตสถานะที่ได้มาเมื่อค่าที่ขึ้นอยู่กับสถานะดังกล่าวมีการเปลี่ยนแปลงจะดีกว่า
computed() ช่วยให้คุณแสดงสัญญาณที่ได้ค่าจากสัญญาณอื่นๆ ได้อย่างชัดเจน
แปลง solvedMessage เป็น computed()
solvedMessage จะแปลค่า secretMessage จากที่เข้ารหัสเป็นที่ถอดรหัสโดยใช้สัญญาณ decodedCipher
ซึ่งเป็นเรื่องที่น่าสนใจมากเนื่องจากคุณจะเห็นว่าคุณกำลังสร้างค่าที่คำนวณแล้วโดยอิงตามค่าที่คำนวณแล้วอีกค่าหนึ่ง ดังนั้นเมื่อใดก็ตามที่สัญญาณภายในบริบทรีแอกทีฟที่แมปไว้มีการเปลี่ยนแปลง ระบบจะแจ้งเตือนการอ้างอิง
ปัจจุบันระบบจะไม่solvedMessageเมื่อคุณเปลี่ยน secretMessage, decodedCipher หรือ superSecretMessage คุณจึงไม่เห็นการอัปเดตบนหน้าจอเมื่อผู้เล่นถอดรหัส
การทำให้ solvedMessage เป็นค่าที่คำนวณแล้วจะสร้างบริบทแบบรีแอกทีฟเพื่อให้เมื่ออัปเดตข้อความหรือแก้ปริศนา คุณจะสามารถรับการอัปเดตสถานะจากการอ้างอิงที่ติดตามได้
หากต้องการแปลง solvedMessage เป็น computed() ให้ทำตามขั้นตอนต่อไปนี้ภายใต้TODO(2): Define your first computed()ความคิดเห็นในแต่ละไฟล์
- ในไฟล์
service.message.tsให้ใช้ไลบรารี Signals เพื่อทำให้solvedMessageมีการโต้ตอบ
src/app/secret-message/service.message.ts
solvedMessage = computed(() =>
this.translateMessage(
this.secretMessage(),
this.cipher.decodedCipher()
)
);
ซึ่งจะแจ้งให้คุณนําเข้า computed จาก @angular/core โดยอัตโนมัติ หากรีเฟรชหน้าเว็บ คุณอาจพบข้อผิดพลาดในตำแหน่งที่คุณเคยอ้างอิงถึง solvedMessage เนื่องจากคุณได้เปลี่ยนประเภทของ superSecretMessage จาก string เป็น Signal<string> ซึ่งเป็นฟังก์ชัน คุณแก้ไขปัญหานี้ได้โดยเปลี่ยนการอ้างอิงทั้งหมดของ solvedMessage เป็น solvedMessage()
- ในไฟล์
secret-message.tsให้อัปเดตการอ้างอิงทั้งหมดของsolvedMessageเป็นsolvedMessage()โดยทำดังนี้
src/app/secret-message/secret-message.ts
// Before
<span *ngFor="let char of this.messages.solvedMessage.split(''); index as i;" [class.unsolved]="this.messages.solvedMessage[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>
// After
<span *ngFor="let char of this.messages.solvedMessage().split(''); index as i;" [class.unsolved]="this.messages.solvedMessage()[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>
โปรดทราบว่า solvedMessage ไม่ใช่ SettableSignal เหมือนกับ superSecretMessage คุณจึงเปลี่ยนค่าของ solvedMessage โดยตรงไม่ได้ แต่ระบบจะอัปเดตค่าของแอตทริบิวต์นี้ทุกครั้งที่มีการอัปเดตสัญญาณการอ้างอิง (secretMessage และ decodedCipher)
สำรวจcomputed() ฟังก์ชันอื่นๆ อีก 2 ฟังก์ชัน
- โปรดสังเกตว่าคุณมีค่าที่คำนวณแล้วอื่นๆ อีก 2 ค่าในแอป ดังนี้
src/app/secret-message/service.message.ts
secretMessage = computed(() =>
this.translateMessage(
this.superSecretMessage(),
this.cipher.cipher()
)
);
src/app/cipher/service.cipher.ts
unsolvedAlphabet = computed(() =>
ALPHABET.filter(
(letter) => !this.decodedCipher().find((guess) => guess.value === letter)
)
);
MessageService จะกำหนด secretMessage ที่คำนวณแล้ว ซึ่งsuperSecretMessage เข้ารหัสโดย cipher ที่ผู้เล่นต้องไข
CipherService จะกำหนด unsolvedAlphabet ที่คำนวณแล้ว ซึ่งเป็นรายการตัวอักษรทั้งหมดที่ผู้เล่นยังไม่ได้ไข ซึ่งได้มาจากรายการคีย์รหัสที่ไขแล้วใน decodedCipher
ยืนยันการเปลี่ยนแปลง
ตอนนี้ superSecretMessage เป็นสัญญาณและ solvedMessage เป็นค่าที่คำนวณแล้ว แอปควรทำงานได้ ทดสอบฟังก์ชันการทำงานของเกม
- ลากและวาง
LetterGuessComponentไปยังLetterKeyComponentในCipherComponentเพื่อไขปริศนาและถอดรหัสข้อความลับ - ดูว่า
SecretMessageComponentอัปเดตอย่างไรเมื่อคุณถอดรหัสข้อความลับได้มากขึ้น - คลิกปรับแต่งเพื่อเปลี่ยนผู้ส่งและข้อความ จากนั้นคลิกสร้างและคัดลอก URL เพื่อดูค่าบนหน้าจอและการเปลี่ยนแปลง URL
- เคล็ดลับ: คัดลอกและวาง URL ลงในแท็บใหม่ หรือแชร์กับเพื่อน แล้วดูว่าระบบจัดเก็บผู้ส่งและข้อความใน URL อย่างไร

6. เพิ่มเอฟเฟกต์แรก()
บางครั้งคุณอาจต้องการให้เกิดบางอย่างเมื่อสัญญาณมีค่าใหม่ effect() ช่วยให้คุณกำหนดเวลาและเรียกใช้ฟังก์ชันตัวแฮนเดิลเพื่อตอบสนองต่อการเปลี่ยนแปลงของสัญญาณได้
เพิ่มกระดาษสีเมื่อไขปริศนาได้
ตอนนี้แอปใช้งานได้แล้ว คุณสามารถเพิ่มความสนุกด้วยการใส่กระดาษโปรยเมื่อไขปริศนาและถอดรหัสข้อความลับได้
หากต้องการเพิ่มกระดาษโปรย ให้ทำตามขั้นตอนต่อไปนี้ในความคิดเห็น TODO(3): Add your first effect()
- ในไฟล์
cipher.tsให้กำหนดเวลาเอฟเฟกต์เพื่อเพิ่มกระดาษสีโปรยปรายเมื่อมีการถอดรหัสข้อความ
src/app/cipher/cipher.ts
import * as confetti from 'canvas-confetti';
ngOnInit(): void {
...
effect(() => {
if (this.messages.superSecretMessage() === this.messages.solvedMessage()) {
var confettiCanvas = document.getElementById('confetti-canvas');
confetti.create()(confettiCanvas, { particleCount: 100 });
}
});
}
โปรดสังเกตว่าเอฟเฟกต์นี้ขึ้นอยู่กับสัญญาณและค่าที่คำนวณแล้ว: this.messages.superSecretMessage() และ this.messages.solvedMessage()
เอฟเฟกต์ช่วยให้คุณกำหนดเวลาฟังก์ชันลูกเล่นภายในบริบทแบบรีแอกทีฟเพื่อติดตามและประเมินซ้ำเมื่อมีการอัปเดตการอ้างอิง
ยืนยันการเปลี่ยนแปลง
- ลองถอดรหัส (คำใบ้: คุณเปลี่ยนข้อความให้สั้นลงเพื่อทดสอบได้เร็วขึ้น) ป๊อปอัปแถบกระดาษสีโปรยปรายจะแสดงขึ้นเพื่อแสดงความยินดีกับคุณที่ได้รับ
effect()แรก

7. ยินดีด้วย
ตอนนี้ Angular Cipher พร้อมที่จะถอดรหัสและแชร์ข้อความลับแล้ว หากมีข้อความสำหรับทีม Angular แท็กโซเชียลมีเดียของเราที่ @Angular เพื่อให้เราถอดรหัสได้ 🎉

ตอนนี้คุณมี Reactive Primitive ใหม่ 3 รายการในกล่องเครื่องมือ Angular เพื่อลดความซับซ้อนในการพัฒนาและสร้างแอปได้เร็วขึ้นโดยค่าเริ่มต้น
ดูข้อมูลเพิ่มเติม
ลองใช้ Codelab เหล่านี้
อ่านเนื้อหาต่อไปนี้
- Angular.io
- การคิดใหม่เกี่ยวกับความสามารถในการตอบสนองด้วย Signals (Google I/O 2023)
- มีอะไรใหม่ใน Angular (Google I/O 2023)