היכרות עם Firebase לאינטרנט

1. סקירה כללית

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

צילום מסך של השלב הזה

מה תלמדו

  • אימות משתמשים באמצעות אימות ב-Firebase ו-FirebaseUI.
  • סנכרון נתונים באמצעות Cloud Firestore.
  • כתיבת כללי אבטחה של Firebase לאבטחת מסד נתונים.

מה צריך להכין

  • דפדפן לבחירתכם, כמו Chrome.
  • גישה אל stackblitz.com (לא נדרש חשבון או כניסה).
  • חשבון Google, כמו חשבון Gmail. מומלץ להשתמש בחשבון האימייל שבו אתם כבר משתמשים בחשבון GitHub. כך תוכלו להשתמש בתכונות המתקדמות של StackBlitz.
  • קוד לדוגמה ב-codelab. בשלב הבא מוסבר איך לקבל את הקוד.

2. קבלת קוד ההתחלה

בקודלאב הזה תלמדו איך ליצור אפליקציה באמצעות StackBlitz, עורך אונליין שמשולב בו מספר תהליכי עבודה של Firebase. כדי להשתמש ב-Stackblitz לא צריך להתקין תוכנה או חשבון StackBlitz מיוחד.

ב-StackBlitz אפשר לשתף פרויקטים עם אחרים. אנשים אחרים שיש להם את כתובת ה-URL של הפרויקט ב-StackBlitz יכולים לראות את הקוד שלכם ליצור ענף (fork) של הפרויקט, אבל הם לא יכולים לערוך את הפרויקט ב-StackBlitz.

  1. עוברים לכתובת ה-URL הזו כדי לקבל את הקוד ההתחלתי: https://stackblitz.com/edit/firebase-gtk-web-start
  2. בחלק העליון של הדף ב-StackBlitz, לוחצים על Fork:

צילום מסך של השלב הזה

עכשיו יש לכם עותק של קוד ההתחלה כפרויקט משלכם ב-StackBlitz, עם שם ייחודי וכתובת URL ייחודית. כל הקבצים והשינויים נשמרים בפרויקט הזה ב-StackBlitz.

3. עריכת פרטי האירוע

חומרי ההתחלה של סדנת הקוד הזו מספקים מבנה מסוים לאפליקציית האינטרנט, כולל כמה גיליונות סגנונות וכמה קונטיינרים של HTML לאפליקציה. בהמשך סדנת הקוד הזו, תקשרו את הקונטיינרים האלה ל-Firebase.

כדי להתחיל, נכיר קצת יותר את הממשק של StackBlitz.

  1. ב-StackBlitz, פותחים את הקובץ index.html.
  2. מאתרים את event-details-container ואת description-container ומנסים לערוך כמה פרטי אירוע.

בזמן העריכה של הטקסט, הדף ייטען מחדש באופן אוטומטי ב-StackBlitz ויוצגו בו פרטי האירוע החדשים. מגניב, נכון?

<!-- ... -->

<div id="app">
  <img src="..." />

  <section id="event-details-container">
     <h1>Firebase Meetup</h1>

     <p><i class="material-icons">calendar_today</i> October 30</p>
     <p><i class="material-icons">location_city</i> San Francisco</p>

  </section>

  <hr>

  <section id="firebaseui-auth-container"></section>

  <section id="description-container">
     <h2>What we'll be doing</h2>
     <p>Join us for a day full of Firebase Workshops and Pizza!</p>
  </section>
</div>

<!-- ... -->

התצוגה המקדימה של האפליקציה אמורה להיראות כך:

תצוגה מקדימה של האפליקציה

צילום מסך של השלב הזה

4. יצירת פרויקט Firebase והגדרתו

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

יצירת פרויקט Firebase

  1. נכנסים ל-Firebase.
  2. במסוף Firebase, לוחצים על Add Project (הוספת פרויקט) (או על Create a project (יצירת פרויקט)), נותנים שם לפרויקט ב-Firebase – Firebase-Web-Codelab.

    צילום מסך של השלב הזה

  3. לוחצים על האפשרויות ליצירת פרויקט. מאשרים את התנאים של Firebase אם מופיעה בקשה לעשות זאת. במסך של Google Analytics, לוחצים על 'לא להפעיל' כי לא תשתמשו ב-Analytics באפליקציה הזו.

מידע נוסף על פרויקטים ב-Firebase זמין במאמר הסבר על פרויקטים ב-Firebase.

הפעלה והגדרה של מוצרי Firebase במסוף

באפליקציה שאתם מפתחים נעשה שימוש בכמה מוצרים של Firebase שזמינים לאפליקציות אינטרנט:

  • אימות ב-Firebase וממשק המשתמש של Firebase כדי לאפשר למשתמשים להיכנס לאפליקציה בקלות.
  • Cloud Firestore כדי לשמור נתונים מובְנים בענן ולקבל התראות מיידיות כשהנתונים משתנים.
  • כללי אבטחה של Firebase לאבטחת מסד הנתונים.

חלק מהמוצרים האלה דורשים הגדרה מיוחדת או צריך להפעיל אותם באמצעות מסוף Firebase.

הפעלת כניסה באמצעות אימייל לאימות ב-Firebase

כדי לאפשר למשתמשים להיכנס לאפליקציית האינטרנט, תשתמשו בשיטת הכניסה כתובת אימייל/סיסמה בקודלאב הזה:

  1. בחלונית הימנית של מסוף Firebase, לוחצים על Build (פיתוח) > Authentication (אימות). לאחר מכן לוחצים על שנתחיל?. עכשיו אתם נמצאים במרכז הבקרה של אימות המשתמשים, שבו אפשר לראות את המשתמשים שנרשמו, להגדיר ספקי כניסה ולנהל את ההגדרות.

    צילום מסך של השלב הזה

  2. בוחרים בכרטיסייה Sign-in method (או לוחצים כאן כדי לעבור ישירות לכרטיסייה).

    צילום מסך של השלב הזה

  3. לוחצים על Email/Password (אימייל/סיסמה) מתוך אפשרויות הספק, מעבירים את המתג למצב Enable (הפעלה) ולוחצים על Save (שמירה).

    צילום מסך של השלב הזה

הגדרת Cloud Firestore

אפליקציית האינטרנט משתמשת ב-Cloud Firestore כדי לשמור הודעות צ'אט ולקבל הודעות צ'אט חדשות.

כך מגדירים את Cloud Firestore בפרויקט Firebase:

  1. בחלונית הימנית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Firestore database.
  2. לוחצים על Create database.
  3. משאירים את הערך (default) בשדה Database ID.
  4. בוחרים מיקום למסד הנתונים ולוחצים על הבא.
    באפליקציה אמיתית, כדאי לבחור מיקום קרוב למשתמשים.
  5. לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור לגבי כללי האבטחה.
    בהמשך הסדנה תוסיפו כללי אבטחה כדי לאבטח את הנתונים. אסור להפיץ או לחשוף אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה למסד הנתונים.
  6. לוחצים על יצירה.

5. הוספה והגדרה של Firebase

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

הוספת ספריות Firebase

כדי שהאפליקציה תשתמש ב-Firebase, צריך להוסיף את ספריות Firebase לאפליקציה. יש כמה דרכים לעשות זאת, כפי שמתואר במסמכי התיעוד של Firebase. לדוגמה, אפשר להוסיף את הספריות מ-CDN של Google, או להתקין אותן באופן מקומי באמצעות npm ולאחר מכן לארוז אותן באפליקציה אם אתם משתמשים ב-Browserify.

ב-StackBlitz יש קיבוץ אוטומטי, כך שאפשר להוסיף את ספריות Firebase באמצעות הצהרות ייבוא. תשתמשו בגרסאות המודולריות (v9) של הספריות, שבעזרתן תוכלו לצמצם את הגודל הכולל של דף האינטרנט באמצעות תהליך שנקרא 'ניעור עץ'. מידע נוסף על ערכות ה-SDK המודולריות זמין במסמכי העזרה.

כדי לפתח את האפליקציה הזו, משתמשים בספריות Firebase Authentication,‏ FirebaseUI ו-Cloud Firestore. בקודלאב הזה, הצהרות הייבוא הבאות כבר כלולות בחלק העליון של הקובץ index.js, ואנחנו נייבא שיטות נוספות מכל ספריית Firebase בהמשך:

// Import stylesheets
import './style.css';

// Firebase App (the core Firebase SDK) is always required
import { initializeApp } from 'firebase/app';

// Add the Firebase products and methods that you want to use
import {} from 'firebase/auth';
import {} from 'firebase/firestore';

import * as firebaseui from 'firebaseui';

הוספת אפליקציית אינטרנט של Firebase לפרויקט Firebase

  1. חוזרים למסוף Firebase ולוחצים על Project Overview (סקירה כללית של הפרויקט) בפינה הימנית העליונה כדי לעבור לדף הסקירה הכללית של הפרויקט.
  2. במרכז דף הסקירה הכללית של הפרויקט, לוחצים על סמל האינטרנט סמל של אפליקציה לאינטרנט כדי ליצור אפליקציית אינטרנט חדשה ב-Firebase.

    צילום מסך של השלב הזה

  3. רושמים את האפליקציה עם הכינוי אפליקציית אינטרנט.
  4. בקודלאב הזה, אל תסמנו את התיבה לצד Also set up Firebase Hosting for this app (גם להגדיר אירוח ב-Firebase לאפליקציה הזו). בשלב הזה תשתמשו בחלונית התצוגה המקדימה של StackBlitz.
  5. לוחצים על Register app (רישום האפליקציה).

    צילום מסך של השלב הזה

  6. מעתיקים את אובייקט התצורה של Firebase ללוח.

    צילום מסך של השלב הזה

  7. לוחצים על Continue to console (המשך למסוף). מוסיפים לאפליקציה את אובייקט התצורה של Firebase:
  8. חוזרים ל-StackBlitz ועוברים לקובץ index.js.
  9. מאתרים את שורת התגובה Add Firebase project configuration object here ומדביקים את קטע הקוד של ההגדרות מתחת לתגובה.
  10. מוסיפים את קריאת הפונקציה initializeApp כדי להגדיר את Firebase באמצעות ההגדרות הייחודיות של פרויקט Firebase.
    // ...
    // Add Firebase project configuration object here
    const firebaseConfig = {
      apiKey: "random-unique-string",
      authDomain: "your-projectId.firebaseapp.com",
      databaseURL: "https://your-projectId.firebaseio.com",
      projectId: "your-projectId",
      storageBucket: "your-projectId.firebasestorage.app",
      messagingSenderId: "random-unique-string",
      appId: "random-unique-string",
    };
    
    // Initialize Firebase
    initializeApp(firebaseConfig);
    

6. הוספת כניסה של משתמש (אישור השתתפות)

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

אימות משתמשים באמצעות כניסה באמצעות אימייל ו-FirebaseUI

תצטרכו להוסיף לחצן 'אישור' שיגרום למשתמש להיכנס באמצעות כתובת האימייל שלו. כדי לעשות זאת, מחברים את FirebaseUI ללחצן אישור השתתפות.FirebaseUI היא ספרייה שמספקת ממשק משתמש מובנה מראש מעל Firebase Auth.

כדי להשתמש ב-FirebaseUI, צריך להגדיר אותו (אפשרויות נוספות מפורטות במסמכי התיעוד). ההגדרה הזו מבצעת שני דברים:

  • הקוד הזה מורה ל-FirebaseUI להשתמש בשיטת הכניסה כתובת אימייל/סיסמה.
  • פונקציה שמטפלת בקריאה החוזרת לאחר כניסה מוצלחת ומחזירה false כדי למנוע הפניה אוטומטית. אתם לא רוצים שהדף ירענן כי אתם מפתחים אפליקציית אינטרנט של דף יחיד.

הוספת הקוד לאתחול של FirebaseUI Auth

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. בחלק העליון, מאתרים את הצהרת הייבוא firebase/auth ומוסיפים את getAuth ו-EmailAuthProvider, כך:
    // ...
    // Add the Firebase products and methods that you want to use
    import { getAuth, EmailAuthProvider } from 'firebase/auth';
    
    import {} from 'firebase/firestore';
    
  3. שומרים הפניה לאובייקט האימות מיד אחרי initializeApp, כך:
    initializeApp(firebaseConfig);
    auth = getAuth();
    
  4. שימו לב שהגדרת FirebaseUI כבר קיימת בקוד ההתחלה. הוא כבר מוגדר להשתמש בספק האימות של האימייל.
  5. בתחתית הפונקציה main() בקובץ index.js, מוסיפים את משפט האתחול של FirebaseUI, כך:
    async function main() {
      // ...
    
      // Initialize the FirebaseUI widget using Firebase
      const ui = new firebaseui.auth.AuthUI(auth);
    }
    main();
    
    

הוספת לחצן לאישור ההשתתפות ל-HTML

  1. ב-StackBlitz, עוברים לקובץ index.html.
  2. מוסיפים את ה-HTML של לחצן אישור השתתפות בתוך ה-event-details-container, כמו בדוגמה שבהמשך.

    חשוב להשתמש באותם ערכי id שמוצגים בהמשך, כי בקודלאב הזה כבר יש הוקס למזהים הספציפיים האלה בקובץ index.js.

    שימו לב שבקובץ index.html יש מאגר עם המזהה firebaseui-auth-container. זהו המזהה שתעבירו ל-FirebaseUI כדי לשמור את ההתחברות.
    <!-- ... -->
    
    <section id="event-details-container">
        <!-- ... -->
        <!-- ADD THE RSVP BUTTON HERE -->
        <button id="startRsvp">RSVP</button>
    </section>
    <hr>
    <section id="firebaseui-auth-container"></section>
    <!-- ... -->
    
    תצוגה מקדימה של האפליקציה

    צילום מסך של השלב הזה

  3. מגדירים מאזין על לחצן אישור ההשתתפות ומפעילים את פונקציית ההתחלה של FirebaseUI. הפעולה הזו מאפשרת ל-FirebaseUI להציג את חלון הכניסה.

    מוסיפים את הקוד הבא לתחתית הפונקציה main() ב-index.js:
    async function main() {
      // ...
    
      // Listen to RSVP button clicks
      startRsvpButton.addEventListener("click",
       () => {
            ui.start("#firebaseui-auth-container", uiConfig);
      });
    }
    main();
    

בדיקת הכניסה לאפליקציה

  1. בחלון התצוגה המקדימה של StackBlitz, לוחצים על הלחצן 'אישור' כדי להיכנס לאפליקציה.
    • בקודלאב הזה אפשר להשתמש בכל כתובת אימייל, גם כתובת אימייל מזויפת, כי לא מגדירים שלב אימות אימייל בקודלאב הזה.
    • אם מופיעה הודעת השגיאה auth/operation-not-allowed או The given sign-in provider is disabled for this Firebase project, צריך לוודא שהפעלתם את אימייל/סיסמה כספק כניסה במסוף Firebase.
    תצוגה מקדימה של האפליקציה

    צילום מסך של השלב הזה

  2. עוברים למרכז הבקרה של אימות במסוף Firebase. בכרטיסייה משתמשים אמורים להופיע פרטי החשבון שהזנתם כדי להיכנס לאפליקציה.

    צילום מסך של השלב הזה

הוספת מצב האימות לממשק המשתמש

בשלב הבא, מוודאים שממשק המשתמש משקף את העובדה שנכנסתם לחשבון.

תשתמשו ב-call back של מאזין המצב של אימות Firebase, שמקבל התראה בכל פעם שסטטוס הכניסה של המשתמש משתנה. אם יש כרגע משתמש שמחובר לחשבון, הלחצן 'הצטרפות' באפליקציה יוחלף בלחצן 'יציאה'.

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. בחלק העליון, מאתרים את הצהרת הייבוא firebase/auth ומוסיפים את signOut ו-onAuthStateChanged, כך:
    // ...
    // Add the Firebase products and methods that you want to use
    import {
      getAuth,
      EmailAuthProvider,
      signOut,
      onAuthStateChanged
    } from 'firebase/auth';
    
    import {} from 'firebase/firestore';
    
  3. מוסיפים את הקוד הבא לתחתית הפונקציה main():
    async function main() {
      // ...
    
      // Listen to the current Auth state
      onAuthStateChanged(auth, user => {
        if (user) {
          startRsvpButton.textContent = 'LOGOUT';
        } else {
          startRsvpButton.textContent = 'RSVP';
        }
      });
    }
    main();
    
  4. בקוד של מאזין הלחצן, בודקים אם יש משתמש פעיל ומוציאים אותו מהחשבון. כדי לעשות זאת, מחליפים את startRsvpButton.addEventListener הנוכחי בקוד הבא:
    // ...
    // Called when the user clicks the RSVP button
    startRsvpButton.addEventListener('click', () => {
      if (auth.currentUser) {
        // User is signed in; allows user to sign out
        signOut(auth);
      } else {
        // No user is signed in; allows user to sign in
        ui.start('#firebaseui-auth-container', uiConfig);
      }
    });
    

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

תצוגה מקדימה של האפליקציה

צילום מסך של השלב הזה

7. כתיבת הודעות ב-Cloud Firestore

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

כדי לאחסן את הודעות הצ'אט שהמשתמשים כותבים באפליקציה, תשתמשו ב-Cloud Firestore.

מודל נתונים

Cloud Firestore הוא מסד נתונים מסוג NoSQL, והנתונים שמאוחסנים במסד הנתונים מחולקים לאוספים, למסמכים, לשדות ולאוספים משניים. כל הודעה בצ'אט תישמר כמסמך באוסף ברמה העליונה שנקרא guestbook.

איור של מודל הנתונים של Firestore שבו מוצג אוסף של אלבום כתובות עם כמה מסמכי הודעות

הוספת הודעות ל-Firestore

בקטע הזה תוסיפו את הפונקציונליות שמאפשרת למשתמשים לכתוב הודעות חדשות במסד הנתונים. קודם מוסיפים את ה-HTML של רכיבי ממשק המשתמש (שדה ההודעה ולחצן השליחה). לאחר מכן מוסיפים את הקוד שמקשר את הרכיבים האלה למסד הנתונים.

כדי להוסיף את רכיבי ממשק המשתמש של שדה הודעה ולחצן שליחה:

  1. ב-StackBlitz, עוברים לקובץ index.html.
  2. מאתרים את guestbook-container ומוסיפים את הקוד הבא ב-HTML כדי ליצור טופס עם שדה להזנת הודעה ולחצן שליחה.
    <!-- ... -->
    
     <section id="guestbook-container">
       <h2>Discussion</h2>
    
       <form id="leave-message">
         <label>Leave a message: </label>
         <input type="text" id="message">
         <button type="submit">
           <i class="material-icons">send</i>
           <span>SEND</span>
         </button>
       </form>
    
     </section>
    
    <!-- ... -->
    

תצוגה מקדימה של האפליקציה

צילום מסך של השלב הזה

לחיצה של משתמש על הלחצן SEND תפעיל את קטע הקוד הבא. הפונקציה מוסיפה את התוכן של שדה הקלט של ההודעה לאוסף guestbook של מסד הנתונים. באופן ספציפי, השיטה addDoc מוסיפה את תוכן ההודעה למסמך חדש (עם מזהה שנוצר באופן אוטומטי) באוסף guestbook.

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. בחלק העליון, מאתרים את משפט הייבוא firebase/firestore ומוסיפים את getFirestore,‏ addDoc ו-collection, כך:
    // ...
    
    // Add the Firebase products and methods that you want to use
    import {
      getAuth,
      EmailAuthProvider,
      signOut,
      onAuthStateChanged
    } from 'firebase/auth';
    
    import {
      getFirestore,
      addDoc,
      collection
    } from 'firebase/firestore';
    
  3. עכשיו נשמור הפניה לאובייקט db ב-Firestore מיד אחרי initializeApp:
    initializeApp(firebaseConfig);
    auth = getAuth();
    db = getFirestore();
    
  4. בתחתית הפונקציה main(), מוסיפים את הקוד הבא.

    הערה: הערך auth.currentUser.uid הוא הפניה למזהה הייחודי שנוצר באופן אוטומטי באימות ב-Firebase לכל המשתמשים שמחוברים לחשבון.
    async function main() {
      // ...
    
      // Listen to the form submission
      form.addEventListener('submit', async e => {
        // Prevent the default form redirect
        e.preventDefault();
        // Write a new message to the database collection "guestbook"
        addDoc(collection(db, 'guestbook'), {
          text: input.value,
          timestamp: Date.now(),
          name: auth.currentUser.displayName,
          userId: auth.currentUser.uid
        });
        // clear message input field
        input.value = '';
        // Return false to avoid redirect
        return false;
      });
    }
    main();
    

הצגת ספר האורחים רק למשתמשים שמחוברים לחשבון

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

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. עורכים את הבורר onAuthStateChanged כדי להסתיר ולהציג את ספר האורחים.
    // ...
    
    // Listen to the current Auth state
    onAuthStateChanged(auth, user => {
      if (user) {
        startRsvpButton.textContent = 'LOGOUT';
        // Show guestbook to logged-in users
        guestbookContainer.style.display = 'block';
      } else {
        startRsvpButton.textContent = 'RSVP';
        // Hide guestbook for non-logged-in users
        guestbookContainer.style.display = 'none';
      }
    });
    

בדיקת שליחת הודעות

  1. מוודאים שנכנסתם לאפליקציה.
  2. כותבים הודעה, למשל 'היי', ולוחצים על שליחה.

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

עם זאת, תוכלו לראות את ההודעה החדשה שנוספה במסוף Firebase.

במסוף Firebase, במרכז הבקרה Firestore Database, אמור להופיע האוסף guestbook עם ההודעה שנוספה. אם תמשיכו לשלוח הודעות, אוסף יומני האורחים יכלול הרבה מסמכים, כמו זה:

מסוף Firebase

צילום מסך של השלב הזה

8. קריאת ההודעות

סנכרון הודעות

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

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

תוסיפו קוד שיאזן להודעות חדשות שנוספו מהאפליקציה. קודם כול, מוסיפים קטע ב-HTML כדי להציג הודעות:

  1. ב-StackBlitz, עוברים לקובץ index.html.
  2. ב-guestbook-container, מוסיפים סעיף חדש עם המזהה guestbook.
    <!-- ... -->
    
      <section id="guestbook-container">
       <h2>Discussion</h2>
    
       <form><!-- ... --></form>
    
       <section id="guestbook"></section>
    
     </section>
    
    <!-- ... -->
    

בשלב הבא רושמים את המאזין שמאזין לשינויים בנתונים:

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. בחלק העליון, מאתרים את משפט הייבוא firebase/firestore ומוסיפים את query,‏ orderBy ו-onSnapshot, כך:
    // ...
    import {
      getFirestore,
      addDoc,
      collection,
      query,
      orderBy,
      onSnapshot
    } from 'firebase/firestore';
    
  3. בתחתית הפונקציה main(), מוסיפים את הקוד הבא כדי לעבור בחזרה על כל המסמכים (הודעות בספר האורחים) במסד הנתונים. מידע נוסף על מה שקורה בקוד הזה זמין בהמשך קטע הקוד.
    async function main() {
      // ...
    
      // Create query for messages
      const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc'));
      onSnapshot(q, snaps => {
        // Reset page
        guestbook.innerHTML = '';
        // Loop through documents in database
        snaps.forEach(doc => {
          // Create an HTML entry for each document and add it to the chat
          const entry = document.createElement('p');
          entry.textContent = doc.data().name + ': ' + doc.data().text;
          guestbook.appendChild(entry);
        });
      });
    }
    main();
    

כדי להאזין להודעות במסד הנתונים, יצרתם שאילתה על אוסף ספציפי באמצעות הפונקציה collection. הקוד שלמעלה מקשיב לשינויים באוסף guestbook, שבו מאוחסנות הודעות הצ'אט. ההודעות מסודרות גם לפי תאריך, וניתן להשתמש ב-orderBy('timestamp', 'desc') כדי להציג את ההודעות החדשות ביותר בחלק העליון.

הפונקציה onSnapshot מקבלת שני פרמטרים: השאילתה שבה רוצים להשתמש ופונקציית קריאה חוזרת. פונקציית הקריאה החוזרת מופעלת כשיש שינויים במסמכים שתואמים לשאילתה. למשל, אם הודעה נמחקת, משתנה או מתווספת. מידע נוסף זמין במסמכי העזרה של Cloud Firestore.

בדיקת סנכרון ההודעות

Cloud Firestore מסנכרן נתונים באופן אוטומטי ומיידי עם לקוחות שנרשמו למסד הנתונים.

  • ההודעות שיצרתם מקודם במסד הנתונים אמורות להופיע באפליקציה. אתם יכולים לכתוב הודעות חדשות, והן אמורות להופיע באופן מיידי.
  • אם פותחים את סביבת העבודה בכמה חלונות או כרטיסיות, ההודעות מסונכרנות בזמן אמת בין הכרטיסיות.
  • (אופציונלי) אפשר לנסות למחוק, לשנות או להוסיף הודעות חדשות באופן ידני ישירות בקטע מסד נתונים במסוף Firebase. השינויים אמורים להופיע בממשק המשתמש.

כל הכבוד! אתם קוראים מסמכים של Cloud Firestore באפליקציה שלכם.

תצוגה מקדימה של האפליקציה

צילום מסך של השלב הזה

9. הגדרת כללי אבטחה בסיסיים

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

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

אפשר לכתוב כללי אבטחה ל-Cloud Firestore במסוף Firebase:

  1. בקטע Build במסוף Firebase, לוחצים על Firestore Database ובוחרים בכרטיסייה Rules (או לוחצים כאן כדי לעבור ישירות לכרטיסייה Rules).
  2. אמורים להופיע כללי האבטחה הבאים שמוגדרים כברירת מחדל, עם מגבלה של כמה שבועות מהיום לגישה הציבורית.

צילום מסך של השלב הזה

זיהוי אוספים

קודם כול, מזהים את האוספים שבהם האפליקציה כותבת נתונים.

  1. מוחקים את התנאי הקיים match /{document=**}, כך שהכללים ייראו כך:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
      }
    }
    
  2. ב-match /databases/{database}/documents, מאתרים את האוסף שרוצים לאבטח:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /guestbook/{entry} {
         // You'll add rules here in the next step.
      }
    }
    

הוספת כללי אבטחה

מאחר שהשתמשתם במזהה האימות (Authentication UID) כשדה בכל מסמך ביומן האורחים, אתם יכולים לקבל את מזהה האימות ולאמת שכל מי שמנסה לכתוב במסמך כולל מזהה אימות תואם.

  1. מוסיפים את כללי הקריאה והכתיבה לקבוצת הכללים, כפי שמתואר בהמשך:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /guestbook/{entry} {
          allow read: if request.auth.uid != null;
          allow create:
            if request.auth.uid == request.resource.data.userId;
        }
      }
    }
    
  2. לוחצים על פרסום כדי לפרוס את הכללים החדשים.עכשיו, רק משתמשים מחוברים יכולים לקרוא את ההודעות בספר האורחים (כל הודעה!), אבל אפשר ליצור הודעה רק באמצעות מזהה המשתמש שלכם. בנוסף, אסור לערוך או למחוק הודעות.

הוספת כללי אימות

  1. מוסיפים אימות נתונים כדי לוודא שכל השדות הצפויים נמצאים במסמך:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /guestbook/{entry} {
          allow read: if request.auth.uid != null;
          allow create:
          if request.auth.uid == request.resource.data.userId
              && "name" in request.resource.data
              && "text" in request.resource.data
              && "timestamp" in request.resource.data;
        }
      }
    }
    
  2. לוחצים על פרסום כדי לפרוס את הכללים החדשים.

איפוס רכיבי ה-listener

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

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. מושכים את המאזין onSnapshot של אוסף יומני האורחים לפונקציה חדשה שנקראת subscribeGuestbook. בנוסף, מקצים את התוצאות של פונקציית onSnapshot למשתנה guestbookListener.

    המאזין onSnapshot של Firestore מחזיר פונקציית ביטול הרשמה, שבאמצעותה תוכלו לבטל את המאזין של קובץ ה-snapshot מאוחר יותר.
    // ...
    // Listen to guestbook updates
    function subscribeGuestbook() {
      const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc'));
      guestbookListener = onSnapshot(q, snaps => {
        // Reset page
        guestbook.innerHTML = '';
        // Loop through documents in database
        snaps.forEach(doc => {
          // Create an HTML entry for each document and add it to the chat
          const entry = document.createElement('p');
          entry.textContent = doc.data().name + ': ' + doc.data().text;
          guestbook.appendChild(entry);
        });
      });
    }
    
  3. מוסיפים מתחת פונקציה חדשה בשם unsubscribeGuestbook. בודקים אם המשתנה guestbookListener לא null, ואז קוראים לפונקציה כדי לבטל את המאזין.
    // ...
    // Unsubscribe from guestbook updates
    function unsubscribeGuestbook() {
      if (guestbookListener != null) {
        guestbookListener();
        guestbookListener = null;
      }
    }
    

לבסוף, מוסיפים את הפונקציות החדשות ל-callback של onAuthStateChanged.

  1. מוסיפים את subscribeGuestbook() בתחתית if (user).
  2. מוסיפים את unsubscribeGuestbook() בתחתית ההצהרה else.
    // ...
    // Listen to the current Auth state
    onAuthStateChanged(auth, user => {
      if (user) {
        startRsvpButton.textContent = 'LOGOUT';
        // Show guestbook to logged-in users
        guestbookContainer.style.display = 'block';
        // Subscribe to the guestbook collection
        subscribeGuestbook();
      } else {
        startRsvpButton.textContent = 'RSVP';
        // Hide guestbook for non-logged-in users
        guestbookContainer.style.display = 'none';
        // Unsubscribe from the guestbook collection
        unsubscribeGuestbook();
      }
    });
    

10. שלב בונוס: תרגול של מה שלמדתם

תיעוד סטטוס אישור ההשתתפות של משתתפים

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

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

  1. ב-StackBlitz, עוברים לקובץ index.html.
  2. ב-guestbook-container, מוסיפים קבוצה של לחצני YES ו-NO, כך:
    <!-- ... -->
      <section id="guestbook-container">
       <h2>Are you attending?</h2>
         <button id="rsvp-yes">YES</button>
         <button id="rsvp-no">NO</button>
    
       <h2>Discussion</h2>
    
       <!-- ... -->
    
     </section>
    <!-- ... -->
    

תצוגה מקדימה של האפליקציה

צילום מסך של השלב הזה

בשלב הבא, רושמים את המאזין ללחיצות על לחצנים. אם המשתמש לוחץ על כן, משתמשים במזהה המשתמש לצורכי אימות כדי לשמור את התגובה במסד הנתונים.

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. בחלק העליון, מאתרים את משפט הייבוא firebase/firestore ומוסיפים את doc,‏ setDoc ו-where, כך:
    // ...
    // Add the Firebase products and methods that you want to use
    import {
      getFirestore,
      addDoc,
      collection,
      query,
      orderBy,
      onSnapshot,
      doc,
      setDoc,
      where
    } from 'firebase/firestore';
    
  3. בתחתית הפונקציה main(), מוסיפים את הקוד הבא כדי להאזין לסטטוס אישור ההשתתפות:
    async function main() {
      // ...
    
      // Listen to RSVP responses
      rsvpYes.onclick = async () => {
      };
      rsvpNo.onclick = async () => {
      };
    }
    main();
    
    
  4. לאחר מכן, יוצרים אוסף חדש בשם attendees ומירשם הפניה למסמך אם לוחצים על אחד מהלחצנים של אישור השתתפות. מגדירים את ההפניה הזו ל-true או ל-false, בהתאם ללחצן שבו לוחצים.

    קודם, עבור rsvpYes:
    // ...
    // Listen to RSVP responses
    rsvpYes.onclick = async () => {
      // Get a reference to the user's document in the attendees collection
      const userRef = doc(db, 'attendees', auth.currentUser.uid);
    
      // If they RSVP'd yes, save a document with attendi()ng: true
      try {
        await setDoc(userRef, {
          attending: true
        });
      } catch (e) {
        console.error(e);
      }
    };
    
    לאחר מכן, אותו הדבר עבור rsvpNo, אבל עם הערך false:
    rsvpNo.onclick = async () => {
      // Get a reference to the user's document in the attendees collection
      const userRef = doc(db, 'attendees', auth.currentUser.uid);
    
      // If they RSVP'd yes, save a document with attending: true
      try {
        await setDoc(userRef, {
          attending: false
        });
      } catch (e) {
        console.error(e);
      }
    };
    

עדכון כללי האבטחה

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

איך מאפשרים הוספה לאוסף attendees

תצטרכו לעדכן את הכללים כדי לאפשר הוספה לאוסף attendees.

  1. באוסף attendees, מכיוון שהשתמשתם במזהה UID של האימות בתור שם המסמך, תוכלו לאחזר אותו ולאמת שה-uid של השולח זהה למסמך שהוא כותב. אתם תאפשרו לכולם לקרוא את רשימת הנוכחים (כי אין בה מידע פרטי), אבל רק היוצרים יוכלו לעדכן אותה.
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        // ... //
        match /attendees/{userId} {
          allow read: if true;
          allow write: if request.auth.uid == userId;
        }
      }
    }
    
  2. לוחצים על פרסום כדי לפרוס את הכללים החדשים.

הוספת כללי אימות

  1. מוסיפים כמה כללי אימות נתונים כדי לוודא שכל השדות הצפויים נמצאים במסמך:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        // ... //
        match /attendees/{userId} {
          allow read: if true;
          allow write: if request.auth.uid == userId
              && "attending" in request.resource.data;
    
        }
      }
    }
    
  2. אל תשכחו ללחוץ על פרסום כדי לפרוס את הכללים!

(אופציונלי) עכשיו אפשר לראות את התוצאות של הלחיצה על הלחצנים. נכנסים למרכז הבקרה של Cloud Firestore במסוף Firebase.

קריאת סטטוס אישור ההשתתפות

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

  1. ב-StackBlitz, עוברים לקובץ index.html.
  2. ב-description-container, מוסיפים רכיב חדש עם המזהה number-attending.
    <!-- ... -->
    
     <section id="description-container">
         <!-- ... -->
         <p id="number-attending"></p>
     </section>
    
    <!-- ... -->
    

בשלב הבא, רושמים את המאזין לאוסף attendees ומספרים את מספר התשובות YES:

  1. ב-StackBlitz, עוברים לקובץ index.js.
  2. בתחתית הפונקציה main(), מוסיפים את הקוד הבא כדי להאזין לסטטוס ההזמנה ולספור את הקליקים על כן.
    async function main() {
      // ...
    
      // Listen for attendee list
      const attendingQuery = query(
        collection(db, 'attendees'),
        where('attending', '==', true)
      );
      const unsubscribe = onSnapshot(attendingQuery, snap => {
        const newAttendeeCount = snap.docs.length;
        numberAttending.innerHTML = newAttendeeCount + ' people going';
      });
    }
    main();
    

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

  1. יוצרים פונקציה שבודקת אם למזהה ה-UID הנוכחי של האימות יש רשומה באוסף attendees, ואז מגדירים את מחלקת הלחצן כ-clicked.
    // ...
    // Listen for attendee list
    function subscribeCurrentRSVP(user) {
      const ref = doc(db, 'attendees', user.uid);
      rsvpListener = onSnapshot(ref, doc => {
        if (doc && doc.data()) {
          const attendingResponse = doc.data().attending;
    
          // Update css classes for buttons
          if (attendingResponse) {
            rsvpYes.className = 'clicked';
            rsvpNo.className = '';
          } else {
            rsvpYes.className = '';
            rsvpNo.className = 'clicked';
          }
        }
      });
    }
    
  2. בנוסף, נגדיר פונקציה לביטול ההרשמה. המערכת תשתמש בו כשהמשתמש יוצא מהחשבון.
    // ...
    function unsubscribeCurrentRSVP() {
      if (rsvpListener != null) {
        rsvpListener();
        rsvpListener = null;
      }
      rsvpYes.className = '';
      rsvpNo.className = '';
    }
    
  3. קוראים לפונקציות מהאזין לאימות.
    // ...
    // Listen to the current Auth state
      // Listen to the current Auth state
      onAuthStateChanged(auth, user => {
        if (user) {
          startRsvpButton.textContent = 'LOGOUT';
          // Show guestbook to logged-in users
          guestbookContainer.style.display = 'block';
    
          // Subscribe to the guestbook collection
          subscribeGuestbook();
          // Subscribe to the user's RSVP
          subscribeCurrentRSVP(user);
        } else {
          startRsvpButton.textContent = 'RSVP';
          // Hide guestbook for non-logged-in users
          guestbookContainer.style.display = 'none'
          ;
          // Unsubscribe from the guestbook collection
          unsubscribeGuestbook();
          // Unsubscribe from the guestbook collection
          unsubscribeCurrentRSVP();
        }
      });
    
  4. נסו להתחבר בתור כמה משתמשים ולראות איך המספר גדל בכל לחיצה נוספת על הלחצן כן.

תצוגה מקדימה של האפליקציה

צילום מסך של השלב הזה

11. כל הכבוד!

השתמשתם ב-Firebase כדי ליצור אפליקציית אינטרנט אינטראקטיבית בזמן אמת.

מה עסקנו בו

  • אימות ב-Firebase
  • FirebaseUI
  • Cloud Firestore
  • כללי אבטחה של Firebase

השלבים הבאים

מידע נוסף

איך היה?

נשמח לקבל ממך משוב. עליך למלא טופס (קצר מאוד) כאן.