תחילת העבודה עם Angular Signals

1. לפני שמתחילים

לוגו שחור של Angular

‫Angular Signals מציג שלושה פרימיטיבים ריאקטיביים ל-Angular שאתם מכירים ואוהבים, ומפשט את תהליך הפיתוח ועוזר לכם ליצור אפליקציות מהירות יותר כברירת מחדל.

מה תפַתחו

  • תלמדו על שלושת הפרימיטיבים הריאקטיביים שהוצגו עם Angular Signals: ‏ signal(),‏ computed() ו-effect().
  • שימוש באותות Angular כדי להפעיל משחק צופן Angular. צפנים הם מערכות להצפנה ולפענוח של נתונים. במשחק הזה, המשתמשים יכולים לפענח הודעה סודית על ידי גרירה ושחרור של רמזים כדי לפתור צופן, להתאים אישית את ההודעה ולשתף את כתובת ה-URL כדי לשלוח הודעות סודיות לחברים.

משחק Angular Cypher בסגנון קונסולת משחקים ירוקה וינטג', עם הודעה מוסתרת על המסך: 'Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!'

דרישות מוקדמות

2. קבל את הקוד

כל מה שצריך לפרויקט הזה נמצא ב-Stackblitz. מומלץ להשתמש ב-Stackblitz כדי לעבוד על ה-Codelab הזה. אפשר גם לשכפל את הקוד ולפתוח אותו בסביבת הפיתוח המועדפת.

פותחים את Stackblitz ומריצים את האפליקציה

כדי להתחיל, פותחים את הקישור ל-Stackblitz בדפדפן האינטרנט המועדף:

  1. פותחים כרטיסייה חדשה בדפדפן ועוברים לכתובת https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcipher%2Fservice.cipher.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts
  2. מבצעים Fork ל-Stackblitz כדי ליצור סביבת עבודה משלכם שאפשר לערוך. אפליקציית Stackblitz אמורה להפעיל את האפליקציה באופן אוטומטי, ואז הכול יהיה מוכן.

חלופה: שיבוט המאגר והצגת האפליקציה

אפשר להשתמש ב-VSCode או בסביבת פיתוח משולבת (IDE) מקומית כשיטה חלופית לביצוע ה-codelab הזה:

  1. פותחים כרטיסייה חדשה בדפדפן ועוברים אל https://github.com/angular/codelabs/tree/signals-get-started.
  2. מבצעים Fork ומשכפלים את המאגר, ומשתמשים בפקודה cd codelabs/ כדי לעבור למאגר.
  3. מריצים את הפקודה git checkout signals-get-started כדי לבדוק את הענף של קוד לתחילת הדרך.
  4. פותחים את הקוד ב-VSCode או בסביבת הפיתוח המשולבת (IDE) המועדפת.
  5. כדי להתקין את התלויות שנדרשות להרצת השרת, משתמשים בפקודה npm install.
  6. כדי להריץ את השרת, משתמשים בפקודה ng serve.
  7. פותחים כרטיסייה בדפדפן ועוברים אל http://localhost:4200.

3. הגדרת ערך בסיס

נקודת ההתחלה היא משחק צופן Angular, אבל הוא עדיין לא פועל. התכונות של המשחק יופעלו באמצעות Angular Signals.

משחק Angular Cypher בסגנון קונסולת משחקים ירוקה וינטג', עם הודעה מוסתרת על המסך: 'Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!'

כדי להתחיל, כדאי לעיין בגרסה הסופית של מה שתבנו: Angular Signals Cypher.

  1. צופים בהודעה המוצפנת במסך.
  2. גוררים ומשחררים לחצן של אות בלוח המקשים כדי לנסות לפתור את הצופן ולפענח את ההודעה הסודית.
  3. אם הפעולה מצליחה, אפשר לראות איך ההודעה מתעדכנת כדי לפענח חלקים נוספים מההודעה הסודית.
  4. לוחצים על התאמה אישית כדי לשנות את השולח וההודעה, ואז לוחצים על יצירה והעתקה של כתובת ה-URL כדי לראות את הערכים במסך ואת השינוי בכתובת ה-URL.
  5. בונוס: מעתיקים את כתובת ה-URL ומדביקים אותה בכרטיסייה חדשה, או משתפים אותה עם חבר, כדי לראות איך השולח וההודעה מאוחסנים בכתובת ה-URL.

‫GIF של המשחק Angular Cypher, עם הודעה מוסתרת שמפוענחת על המסך כדי לאיית 'Angular Signals are in developer preview in v16 today!' (התכונה Angular Signals זמינה היום בגרסת טרום-השקה למפתחים בגרסה 16!)

4. הגדרת הפונקציה הראשונה signal()‎

אות הוא ערך שיכול להצביע על שינוי ב-Angular. חלק מהאותות אפשר לשנות ישירות, ואילו אחרים מחשבים את הערכים שלהם מתוך הערכים של אותות אחרים. האותות יוצרים יחד גרף מכוון של תלות, שמדמה את זרימת הנתונים באפליקציה.

‫Angular יכולה להשתמש בהתראות מאותות כדי לדעת אילו רכיבים צריך לזהות שינויים בהם או כדי להפעיל פונקציות של אפקט שהגדרתם.

המרת superSecretMessage ל-signal()

superSecretMessage הוא ערך ב-MessageService שמגדיר את ההודעה הסודית שהשחקן מפענח. בשלב הזה, הערך לא מעדכן את האפליקציה לגבי שינויים, ולכן הלחצן התאמה אישית לא פועל. אפשר לפתור את הבעיה באמצעות אות.

אם הופכים את superSecretMessage לאות, אפשר להודיע לחלקים באפליקציה שתלויים בידיעה מתי ההודעה השתנתה. כשמתאימים אישית את ההודעה בתיבת דו-שיח, מגדירים את האות לעדכון שאר האפליקציה בהודעה החדשה.

כדי להגדיר את האות הראשון, מבצעים את השלבים הבאים מתחת להערה TODO(1): Define your first signal() בכל קובץ:

  1. בקובץ 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. בכל מקום שבו קוראים את הערך, קוראים את הפונקציה Signal getter‏ superSecretMessage(). בכל מקום שבו אתם כותבים את הערך, אתם צריכים להשתמש ב-.set API ב-SettableSignal כדי להגדיר את הערך החדש להודעה.

  1. בקובץ 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()

מידע על שני האותות האחרים

  • שימו לב שיש עוד שני אותות באפליקציה:

src/app/cipher/service.cipher.ts

cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);

התג CipherService מגדיר אות cipher, מיפוי שנוצר באופן אקראי של צמדי מפתח/ערך של אות אחת באלפבית לאות cipher חדשה. המשתמשים משתמשים בזה כדי לערבב את ההודעה ולבדוק אם השחקן מוצא התאמה מוצלחת במקלדת.

יש גם אות decodedCipher של צמדי מפתח/ערך שפוענחו בהצלחה, שתוכלו להוסיף אותם כשהמשתמש יפתור את הצופן.

מאפיין ייחודי וחשוב של עיצוב ספריית ה-Signals של Angular הוא שאפשר להוסיף תגובתיות בכל מקום. הגדרתם את האותות פעם אחת בשירותים של האפליקציה, ואתם יכולים להשתמש בהם בתבנית, ברכיבים, בצינורות, בשירותים אחרים או בכל מקום שבו אתם יכולים לכתוב קוד אפליקציה. הם לא מוגבלים או קשורים להיקף של רכיב.

אימות השינויים

  • יש עוד שלב אחד שצריך לבצע כדי שהאפליקציה תפעל. בינתיים, כדאי להוסיף console.log() בחלקים שונים של האפליקציה כדי לראות איך מוגדר superSecretMessage החדש.

‫Stackblitz עם הודעה של console.log() שמראה שההודעה החדשה נרשמת ביומן של superSecretMessage בצורה נכונה.

5. הגדרת הפונקציה הראשונה computed()

במצבים רבים, יכול להיות שתצטרכו לגזור את הסטטוס מערכים קיימים. עדיף שהעדכון של המצב הנגזר יתבצע כשהערך התלוי משתנה.

באמצעות computed(), אפשר להגדיר אות שמקבל את הערך שלו מאותות אחרים.

המרת solvedMessage ל-computed()

solvedMessage מתרגם את הערך secretMessage מקודד למפוענח באמצעות האות decodedCipher.

זה מגניב במיוחד כי אפשר לראות שאתם גוזרים ערך מחושב על סמך ערך מחושב אחר, כך שבכל פעם שמשתנה אות בהקשר הממופה והתגובתי הזה, התלות מקבלת הודעה.

בשלב הזה, solvedMessage לא מתעדכן כשמשנים את secretMessage, decodedCipher או superSecretMessage. לכן, לא רואים עדכונים במסך כשהשחקן פותר את הצופן.

כשמגדירים את solvedMessage כמאפיין מחושב, יוצרים הקשר תגובתי, כך שכשתעדכנו את ההודעה או תפענחו את הצופן, תוכלו לגזור עדכון של המצב מהתלויות שעוקבים אחריהן.

כדי להמיר את solvedMessage ל-computed(), מבצעים את השלבים הבאים מתחת לתגובה TODO(2): Define your first computed() בכל קובץ:

  1. בקובץ 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().

  1. בקובץ 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>

שימו לב שבניגוד ל-superSecretMessage, ‏ solvedMessage הוא לא SettableSignal – אי אפשר לשנות את הערך שלו ישירות. במקום זאת, הערך שלו מתעדכן בכל פעם שאחד מאותות התלות שלו (secretMessage ו-decodedCipher) מתעדכן.

כדאי לנסות את שתי computed() הפונקציות האחרות

  • שימו לב שיש עוד שני ערכים מחושבים באפליקציה:

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 הוא ערך מחושב, האפליקציה אמורה לפעול. בודקים את הפונקציות של המשחק:

  1. גוררים ומשחררים LetterGuessComponent אל LetterKeyComponent בCipherComponent כדי לנסות לפצח את הצופן ולפענח את ההודעה הסודית.
  2. אפשר לראות איך SecretMessageComponent מתעדכן כשמפענחים עוד חלקים מההודעה הסודית.
  3. לוחצים על התאמה אישית כדי לשנות את השולח וההודעה, ואז לוחצים על יצירה והעתקה של כתובת ה-URL כדי לראות את הערכים במסך ואת השינוי בכתובת ה-URL.
  4. בונוס: מעתיקים את כתובת ה-URL ומדביקים אותה בכרטיסייה חדשה, או משתפים אותה עם חבר, כדי לראות איך השולח וההודעה מאוחסנים בכתובת ה-URL.

‫GIF של המשחק Angular Cypher, עם הודעה מוסתרת שמפוענחת על המסך כדי לאיית &#39;Angular Signals are in developer preview in v16 today!&#39; (התכונה Angular Signals זמינה היום בגרסת טרום-השקה למפתחים בגרסה 16!)

6. הוספת האפקט הראשון()

לפעמים רוצים שמשהו יקרה כשלאות יש ערך חדש. באמצעות effect(), אפשר לתזמן ולהפעיל פונקציית handler בתגובה לשינויים ב-signals.

הוספת קונפטי כשפותרים את הצופן

עכשיו שהאפליקציה פועלת, אפשר להוסיף קצת כיף על ידי הוספת קונפטי כשהצופן נפתר וההודעה הסודית מפוענחת.

כדי להוסיף קונפטי, מבצעים את השלבים הבאים מתחת לתג התגובה TODO(3): Add your first effect():

  1. בקובץ 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() הראשון שלכם.

קובץ GIF של המשחק Angular Cypher, עם הודעה מוסתרת שמפוענחת על המסך כדי לאיית &#39;Confetti time!‎&#39; (הגיע הזמן לקונפטי!) וקונפטי שמופיע כשפותרים את ההודעה.

7. מעולה!

הצופן שלכם ב-Angular מוכן עכשיו לפענוח ולשיתוף של הודעות סודיות. רוצים לשלוח הודעה לצוות Angular? תייגו אותנו ברשתות החברתיות בכתובת ‎ @Angular כדי שנוכל לפענח את זה! 🎉

משחק Angular Cypher שנפתר עם הודעה מוסתרת במסך של &#39;Angular Signals are in developer preview in v16 today!&#39;

עכשיו יש לכם שלושה פרימיטיבים ריאקטיביים חדשים בארגז הכלים של Angular, שיעזרו לכם לפשט את הפיתוח ולבנות אפליקציות מהר יותר כברירת מחדל.

מידע נוסף

כדאי לנסות את ה-Codelabs הבאים:

מומלץ לקרוא את החומרים הבאים: