CINXE.COM

Get to know Firebase for web

<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="721724668570-nbkv1cfusk7kk4eni4pjvepaus73b13t.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="Firebase"> <meta property="og:type" content="website"><meta name="theme-color" content="#a8c7fa"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/firebase/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/css/app.css"> <link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/css/dark-theme.css" disabled> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/favicon.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/touchicon-180.png"><link rel="canonical" href="https://firebase.google.com/codelabs/firebase-get-to-know-web"><link rel="search" type="application/opensearchdescription+xml" title="Firebase" href="https://firebase.google.com/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://firebase.google.com/codelabs/firebase-get-to-know-web" /><link rel="alternate" hreflang="x-default" href="https://firebase.google.com/codelabs/firebase-get-to-know-web" /><link rel="alternate" hreflang="ar" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=ar" /><link rel="alternate" hreflang="bn" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=bn" /><link rel="alternate" hreflang="zh-Hans" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=zh-tw" /><link rel="alternate" hreflang="fa" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=fa" /><link rel="alternate" hreflang="fr" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=fr" /><link rel="alternate" hreflang="de" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=de" /><link rel="alternate" hreflang="he" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=he" /><link rel="alternate" hreflang="hi" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=hi" /><link rel="alternate" hreflang="id" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=id" /><link rel="alternate" hreflang="it" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=it" /><link rel="alternate" hreflang="ja" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=ja" /><link rel="alternate" hreflang="ko" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=ko" /><link rel="alternate" hreflang="pl" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=pl" /><link rel="alternate" hreflang="pt-BR" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=pt-br" /><link rel="alternate" hreflang="pt" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=pt" /><link rel="alternate" hreflang="ru" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=ru" /><link rel="alternate" hreflang="es" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=es" /><link rel="alternate" hreflang="es-419" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=es-419" /><link rel="alternate" hreflang="th" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=th" /><link rel="alternate" hreflang="tr" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=tr" /><link rel="alternate" hreflang="vi" href="https://firebase.google.com/codelabs/firebase-get-to-know-web?hl=vi" /><title>Get to know Firebase for web</title> <meta property="og:title" content="Get to know Firebase for web"><meta name="description" content="Build a web app from scratch with Firebase and the StackBlitz online editor. You’ll use basic HTML and JavaScript to talk to Firebase. This is a great introduction to using the Firebase console and integrating Firebase into an app. No extensive prior knowledge or software installations are needed."> <meta property="og:description" content="Build a web app from scratch with Firebase and the StackBlitz online editor. You’ll use basic HTML and JavaScript to talk to Firebase. This is a great introduction to using the Firebase console and integrating Firebase into an app. No extensive prior knowledge or software installations are needed."><meta property="og:url" content="https://firebase.google.com/codelabs/firebase-get-to-know-web"><meta property="og:locale" content="en"> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="codelab" theme="firebase-icy-theme" type="codelab" appearance layout="docs" concierge='closed' display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <a href="#main-content" class="skip-link button"> Skip to main content </a> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner" keep-tabs-visible> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="firebase" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup.svg" media="(prefers-color-scheme: dark)" class="devsite-dark-theme" alt="Firebase"> <img src="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup.svg" class="devsite-site-logo" alt="Firebase"> </picture> </a> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion tenant-name="Firebase" > <form class="devsite-search-form" action="https://firebase.google.com/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-appearance-selector></devsite-appearance-selector> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt" >Português</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <a class="devsite-header-link devsite-top-button button gc-analytics-event" href="//console.firebase.google.com" data-category="Site-Wide Custom Events" data-label="Site header link" > Go to console </a> <devsite-user enable-profiles fp-auth id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars hidden> <div class="devsite-book-nav-filter" hidden> <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="firebase" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup.svg" media="(prefers-color-scheme: dark)" class="devsite-dark-theme" alt="Firebase"> <img src="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup.svg" class="devsite-site-logo" alt="Firebase"> </picture> </a> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> <li class="devsite-nav-item"> <a href="//console.firebase.google.com" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Go to console" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Go to console </span> </a> </li> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" id="main-content" class="devsite-main-content" > <devsite-content> <article class="devsite-article"><style> body { transition: opacity ease-in 0.2s; } body[unresolved] { opacity: 0; display: block; overflow: hidden; position: relative; } </style> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" > </ul> </div> <h1 class="devsite-page-title" tabindex="-1"> Get to know Firebase for web </h1> <devsite-feature-tooltip ack-key="AckCollectionsBookmarkTooltipDismiss" analytics-category="Site-Wide Custom Events" analytics-action-show="Callout Profile displayed" analytics-action-close="Callout Profile dismissed" analytics-label="Create Collection Callout" class="devsite-page-bookmark-tooltip nocontent" dismiss-button="true" id="devsite-collections-dropdown" dismiss-button-text="Dismiss" close-button-text="Got it"> <devsite-bookmark></devsite-bookmark> <span slot="popout-heading"> Stay organized with collections </span> <span slot="popout-contents"> Save and categorize content based on your preferences. </span> </devsite-feature-tooltip> <devsite-toc class="devsite-nav" depth="1" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <google-codelab-analytics gaid="UA-49880327-14" ga4id="G-JTFZSJVVVZ"></google-codelab-analytics> <google-codelab codelab-gaid="" codelab-ga4id="" doc-id="" id="firebase-get-to-know-web" title="Get to know Firebase for web" no-tooltip="" environment="web" category="firebase,web" feedback-link="https://forms.gle/53xm9Tva4TgA5Hg47" layout="paginated" > <google-codelab-step label="Overview" duration="1" step="0"> <google-codelab-about codelab-title="Get to know Firebase for web" authors="Kiana McNellis and Rachel Saunders" last-updated="2024-11-01T13:19:31Z" duration="52"> </google-codelab-about> <h2 class="step-title" id="0" data-text="Overview" tabindex="-1"> 1. Overview </h2> <p>In this codelab, you&#39;ll learn some of the basics of <a href="http://firebase.google.com" target="_blank">Firebase</a> to create interactive web applications. You&#39;ll build an event RSVP and guestbook chat app using several Firebase products.</p> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/59abdefbcc23bbbe_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <h2 class="checklist" is-upgraded id="what-youll-learn" data-text="What you'll learn" tabindex="-1"><strong>What you'll learn</strong></h2> <ul class="checklist"> <li>Authenticate users with Firebase Authentication and FirebaseUI.</li> <li>Sync data using Cloud Firestore.</li> <li>Write Firebase Security Rules to secure a database.</li> </ul> <h2 is-upgraded id="what-youll-need" data-text="What you'll need" tabindex="-1"><strong>What you'll need</strong></h2> <ul> <li>A browser of your choice, such as Chrome.</li> <li>Access to <a href="http://stackblitz.com" target="_blank">stackblitz.com</a> (no account or sign-in necessary).</li> <li>A Google account, like a gmail account. We recommend the email account that you already use for your GitHub account. This allows you to use advanced features in StackBlitz.</li> <li>The codelab&#39;s sample code. See the next step for how to get the code.</li> </ul> </google-codelab-step> <google-codelab-step label="Get the starting code" duration="1" step="1"> <h2 class="step-title" id="1" data-text="Get the starting code" tabindex="-1"> 2. Get the starting code </h2> <p>In this codelab, you build an app using <a href="http://www.stackblitz.com" target="_blank">StackBlitz</a>, an online editor that has several Firebase workflows integrated into it. Stackblitz requires no software installation or special StackBlitz account.</p> <p>StackBlitz lets you share projects with others. Other people who have your StackBlitz project URL can see your code and fork your project, but they can&#39;t edit your StackBlitz project.</p> <ol type="1"> <li>Go to this URL for the starting code: <a href="https://stackblitz.com/edit/firebase-gtk-web-start" target="_blank"><strong>https://stackblitz.com/edit/firebase-gtk-web-start</strong></a></li> <li>At the top of the StackBlitz page, click <strong>Fork</strong>:</li> </ol> <p class="image-container"><img alt="screenshot of this step" style="width: 285.50px" src="/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f5135360aef481cc_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <p>You now have a copy of the starting code as your own StackBlitz project, which has a unique name, along with a unique URL. All of your files and changes are saved in this StackBlitz project.</p> <aside class="special"><p>Just in case you happen to get off track, there are StackBlitz links at various checkpoints in this codelab, updated with all of the code added up to that point.</p> <p>Make sure that you do two things at these checkpoints:</p> <ol type="1"> <li>Fork the project so that it&#39;s your own.</li> <li>Add your Firebase project configuration object from the Firebase console (more on that later in the codelab).</li> </ol> </aside> </google-codelab-step> <google-codelab-step label="Edit event information" duration="3" step="2"> <h2 class="step-title" id="2" data-text="Edit event information" tabindex="-1"> 3. Edit event information </h2> <p>The starting materials for this codelab provide some structure for the web app, including some stylesheets and a couple of HTML containers for the app. Later in this codelab, you&#39;ll hook these containers up to Firebase.</p> <p>To get started, let&#39;s get a bit more familiar with the StackBlitz interface.</p> <ol type="1"> <li>In StackBlitz, open the <code translate="no" dir="ltr">index.html</code> file.</li> <li>Locate <code translate="no" dir="ltr">event-details-container</code> and <code translate="no" dir="ltr">description-container</code>, then try editing some event details.</li> </ol> <p>As you edit the text, the automatic page reload in StackBlitz displays the new event details. Cool, yeah?</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="scdoc"><code translate="no" dir="ltr">&lt;!-- ... --&gt; &lt;div id="app"&gt; &lt;img src="..." /&gt; &lt;section id="event-details-container"&gt; &lt;h1&gt;Firebase Meetup&lt;/h1&gt; &lt;p&gt;&lt;i class="material-icons"&gt;calendar_today&lt;/i&gt; October 30&lt;/p&gt; &lt;p&gt;&lt;i class="material-icons"&gt;location_city&lt;/i&gt; San Francisco&lt;/p&gt; &lt;/section&gt; &lt;hr&gt; &lt;section id="firebaseui-auth-container"&gt;&lt;/section&gt; &lt;section id="description-container"&gt; &lt;h2&gt;What we'll be doing&lt;/h2&gt; &lt;p&gt;Join us for a day full of Firebase Workshops and Pizza!&lt;/p&gt; &lt;/section&gt; &lt;/div&gt; &lt;!-- ... --&gt; </code></pre></devsite-code> <p>The preview of your app should look something like this:</p> <h3 is-upgraded id="app-preview" data-text="App preview" tabindex="-1">App preview</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/908cc57ce3a5b5fe_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> </google-codelab-step> <google-codelab-step label="Create and set up a Firebase project" duration="7" step="3"> <h2 class="step-title" id="3" data-text="Create and set up a Firebase project" tabindex="-1"> 4. Create and set up a Firebase project </h2> <p>Displaying the event information is great for your guests, but just showing the events isn&#39;t very useful for anybody. Let&#39;s add some dynamic functionality to this app. For this, you&#39;ll need to hook Firebase up to your app. To get started with Firebase, you&#39;ll need to create and set up a Firebase project.</p> <h2 is-upgraded id="create-a-firebase-project" data-text="Create a Firebase project" tabindex="-1"><strong>Create a Firebase project</strong></h2> <ol type="1"> <li>Sign in to <a href="https://console.firebase.google.com/" target="_blank">Firebase</a>.</li> <li>In the Firebase console, click <strong>Add Project</strong> (or <strong>Create a project</strong>), then name your Firebase project <strong>Firebase-Web-Codelab</strong>. <br><br><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/a67c239f8cc7f4b5_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Click through the project creation options. Accept the Firebase terms if prompted. On the Google Analytics screen, click &#34;Don&#39;t Enable&#34;, because you won&#39;t be using Analytics for this app.</li> </ol> <p>To learn more about Firebase projects, see <a href="https://www.google.com/url?q=https://firebase.google.com/docs/projects/learn-more&sa=D&ust=1568059744191000&usg=AFQjCNEo043D9nD4a1aS2AjK8ReenvZ3Pg" target="_blank">Understand Firebase projects</a>.</p> <h2 is-upgraded id="enable-and-set-up-firebase-products-in-the-console" data-text="Enable and set up Firebase products in the console" tabindex="-1"><strong>Enable and set up Firebase products in the console</strong></h2> <p>The app that you&#39;re building uses several Firebase products that are available for web apps:</p> <ul> <li><strong>Firebase Authentication</strong> and <strong>Firebase UI</strong> to easily allow your users to sign in to your app.</li> <li><strong>Cloud Firestore</strong> to save structured data on the cloud and get instant notification when data changes.</li> <li><strong>Firebase Security Rules</strong> to secure your database.</li> </ul> <p>Some of these products need special configuration or need to be enabled using the Firebase console.</p> <h3 is-upgraded id="enable-email-sign-in-for-firebase-authentication" data-text="Enable email sign-in for Firebase Authentication" tabindex="-1"><strong>Enable email sign-in for Firebase Authentication</strong></h3> <p>To allow users to sign in to the web app, you&#39;ll use the <strong>Email/Password</strong> sign-in method for this codelab:</p> <ol type="1"> <li>In the left-side panel of the Firebase console, click <strong>Build</strong> &gt; <strong>Authentication</strong>. Then click <strong>Get Started</strong>. You&#39;re now in the Authentication dashboard, where you can see signed-up users, configure sign-in providers, and manage settings. <br><br><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/B7iq4DJHEjV9eiZ_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Select the <strong>Sign-in method</strong> tab (or <a href="https://console.firebase.google.com/project/_/authentication/providers" target="_blank">click here</a> to go directly to the tab).<br><br><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/qBxJXqa3Fq2SJcS_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Click <strong>Email/Password</strong> from the provider options, toggle the switch to <strong>Enable</strong>, and then click <strong>Save</strong>.<br><br><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c88427cfd869bee_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> </ol> <h3 is-upgraded id="set-up-cloud-firestore" data-text="Set up Cloud Firestore" tabindex="-1"><strong>Set up Cloud Firestore</strong></h3> <p>The web app uses <a href="https://firebase.google.com/docs/firestore/" target="_blank">Cloud Firestore</a> to save chat messages and receive new chat messages.</p> <p>Here&#39;s how to set up Cloud Firestore in your Firebase project:</p> <ol type="1"> <li>In the left-panel of the Firebase console, expand <strong>Build</strong> and then select <a href="https://console.firebase.google.com/project/_/firestore" target="_blank"><strong>Firestore database</strong></a>.</li> <li>Click <strong>Create database</strong>.</li> <li>Leave the <em>Database ID</em> set to <code translate="no" dir="ltr">(default)</code>.</li> <li>Select a location for your database, then click <em>Next</em>.<br>For a real app, you want to choose a location that&#39;s close to your users.</li> <li>Click <strong>Start in test mode</strong>. Read the disclaimer about the security rules.<br>Later in this codelab, you&#39;ll add Security Rules to secure your data. <strong>Do </strong><strong><em>not</em></strong><strong> distribute or expose an app publicly without adding Security Rules for your database.</strong></li> <li>Click <strong>Create</strong>.</li> </ol> </google-codelab-step> <google-codelab-step label="Add and configure Firebase" duration="5" step="4"> <h2 class="step-title" id="4" data-text="Add and configure Firebase" tabindex="-1"> 5. Add and configure Firebase </h2> <p>Now that you have your Firebase project created and some services enabled, you need to tell the code that you want to use Firebase, as well as which Firebase project to use.</p> <h2 is-upgraded id="add-the-firebase-libraries" data-text="Add the Firebase libraries" tabindex="-1"><strong>Add the Firebase libraries</strong></h2> <p>For your app to use Firebase, you need to add the Firebase libraries to the app. There are multiple ways to do this, as <a href="https://firebase.google.com/docs/web/setup" target="_blank">described in the Firebase documentation</a>. For example, you can add the libraries from Google&#39;s CDN, or you can install them locally using npm and then package them in your app if you&#39;re using Browserify.</p> <p>StackBlitz provides automatic bundling, so you can add the Firebase libraries using import statements. You will be using the modular (v9) versions of the libraries, which help reduce the overall size of the webpage though a process called &#34;tree shaking&#34;. You can learn more about the modular SDKs <a href="https://firebase.google.com/docs/web/learn-more#modular-version" target="_blank">in the docs</a>.</p> <p>To build this app, you use the Firebase Authentication, FirebaseUI, and Cloud Firestore libraries. For this codelab, the following import statements are already included at the top of the <code translate="no" dir="ltr">index.js</code> file, and we&#39;ll be importing more methods from each Firebase library as we go:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Import</span> <span class="devsite-syntax-n">stylesheets</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'./style.css'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">App</span> <span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">the</span> <span class="devsite-syntax-n">core</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">SDK</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-ow">is</span> <span class="devsite-syntax-n">always</span> <span class="devsite-syntax-n">required</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">initializeApp</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/app'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Add</span> <span class="devsite-syntax-n">the</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">products</span> <span class="devsite-syntax-ow">and</span> <span class="devsite-syntax-n">methods</span> <span class="devsite-syntax-n">that</span> <span class="devsite-syntax-n">you</span> <span class="devsite-syntax-n">want</span> <span class="devsite-syntax-n">to</span> <span class="devsite-syntax-n">use</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/auth'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/firestore'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">*</span> <span class="devsite-syntax-k">as</span> <span class="devsite-syntax-n">firebaseui</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebaseui'</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> <h2 is-upgraded id="add-a-firebase-web-app-to-your-firebase-project" data-text="Add a Firebase web app to your Firebase project" tabindex="-1"><strong>Add a Firebase web app to your Firebase project</strong></h2> <ol type="1"> <li>Back in the Firebase console, navigate to your project&#39;s overview page by clicking <strong>Project Overview</strong> in the top left.</li> <li>In the center of your project&#39;s overview page, click the web icon <img alt="web app icon" style="width: 50.00px" src="/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b286f3d215e1f578_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px">to create a new Firebase web app.<br><br><img alt="screenshot of this step" style="width: 247.50px" src="/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c167e9526fad2825_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Register the app with the nickname <strong>Web App</strong>.</li> <li>For this codelab, do NOT check the box next to <strong>Also set up Firebase Hosting for this app</strong>. You&#39;ll use StackBlitz&#39;s preview pane for now.</li> <li>Click <strong>Register app</strong>.<aside class="warning"><p>Stackblitz manages your dependencies for you, so you can skip the <code translate="no" dir="ltr">npm install firebase</code> step that&#39;s displayed in the console.</p> </aside> <br><br><img alt="screenshot of this step" style="width: 496.84px" src="/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/c85ac8aa351e2560_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Copy the <a href="https://firebase.google.com/docs/projects/learn-more#config-files-objects" target="_blank">Firebase configuration object</a> to your clipboard.<br><br><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ed1e598c6132f734_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Click <strong>Continue to console</strong>.Add the Firebase configuration object to your app:</li> <li>Back in StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>Locate the <code translate="no" dir="ltr">Add Firebase project configuration object here</code> comment line, then paste your configuration snippet just below the comment.</li> <li>Add the <code translate="no" dir="ltr">initializeApp</code> function call to set up Firebase using your unique Firebase project configuration.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Firebase</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">project</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">configuration</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">object</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span> <span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">firebaseConfig</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">apiKey</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"random-unique-string"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">authDomain</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"your-projectId.firebaseapp.com"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">databaseURL</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"https://your-projectId.firebaseio.com"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">projectId</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"your-projectId"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">storageBucket</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"your-projectId.firebasestorage.app"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">messagingSenderId</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"random-unique-string"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appId</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"random-unique-string"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-p">};</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Initialize</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">initializeApp</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">firebaseConfig</span><span class="devsite-syntax-p">);</span> </code></pre></devsite-code> </li> </ol> <aside class="special"><p><strong>If you missed the </strong><strong><code translate="no" dir="ltr">firebaseConfig</code></strong> <strong>snippet (or need it at a checkpoint)...</strong></p> <p>You can get your Firebase project configuration object from the Firebase console.</p> <ol type="1"> <li>In the Firebase console, click the settings icon in the top-left corner, then select <strong>Project settings</strong>.</li> <li>In the <strong>General</strong> tab, scroll down to the <strong>Your apps</strong> card.</li> <li>Click on your web app, then select the <strong>Config</strong> option for the Firebase SDK snippet.</li> <li>Copy the entire configuration snippet to your clipboard.</li> </ol> <p class="image-container"><img alt="screenshot of this step" style="width: 610.00px" src="/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/f2c0f5838d0e8202_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </aside> </google-codelab-step> <google-codelab-step label="Add user sign-in (RSVP)" duration="10" step="5"> <h2 class="step-title" id="5" data-text="Add user sign-in (RSVP)" tabindex="-1"> 6. Add user sign-in (RSVP) </h2> <p>Now that you&#39;ve added Firebase to the app, you can set up an RSVP button that registers people using <a href="https://firebase.google.com/docs/auth/web/start" target="_blank">Firebase Authentication</a>.</p> <h2 is-upgraded id="authenticate-your-users-with-email-sign-in-and-firebaseui" data-text="Authenticate your users with Email Sign-In and FirebaseUI" tabindex="-1"><strong>Authenticate your users with Email Sign-In and FirebaseUI</strong></h2> <p>You&#39;ll need an RSVP button that prompts the user to sign in with their email address. You can do this by hooking up <a href="https://firebase.google.com/docs/auth/web/firebaseui" target="_blank">FirebaseUI</a> to an RSVP button.FirebaseUI is a library which gives you a pre-built UI on top of Firebase Auth.</p> <p>FirebaseUI requires a configuration (see the options in the <a href="https://github.com/firebase/firebaseui-web#example-with-all-parameters-used" target="_blank">documentation</a>) that does two things:</p> <ul> <li>Tells FirebaseUI that you want to use the <strong>Email/Password</strong> sign-in method.</li> <li>Handles the callback for a successful sign-in and returns false to avoid a redirect. You don&#39;t want the page to refresh because you&#39;re building a single-page web app.</li> </ul> <h3 is-upgraded id="add-the-code-to-initialize-firebaseui-auth" data-text="Add the code to initialize FirebaseUI Auth" tabindex="-1">Add the code to initialize FirebaseUI Auth</h3> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>At the top, locate the <code translate="no" dir="ltr">firebase/auth</code> import statement, then add <code translate="no" dir="ltr">getAuth</code> and <code translate="no" dir="ltr">EmailAuthProvider</code>, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span> <span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Add</span> <span class="devsite-syntax-n">the</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">products</span> <span class="devsite-syntax-ow">and</span> <span class="devsite-syntax-n">methods</span> <span class="devsite-syntax-n">that</span> <span class="devsite-syntax-n">you</span> <span class="devsite-syntax-n">want</span> <span class="devsite-syntax-n">to</span> <span class="devsite-syntax-n">use</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">getAuth</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">EmailAuthProvider</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/auth'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/firestore'</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> </li> <li>Save a reference to the auth object right after <code translate="no" dir="ltr">initializeApp</code>, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-js" class="language-js" translate="no" dir="ltr">initializeApp(firebaseConfig); auth = getAuth(); </code></pre></devsite-code> </li> <li>Notice that the FirebaseUI configuration is already provided in the starting code. It&#39;s already setup to use the email auth provider.</li> <li>At the bottom of the <code translate="no" dir="ltr">main()</code> function in <code translate="no" dir="ltr">index.js</code>, add the FirebaseUI initialization statement, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-n">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Initialize</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FirebaseUI</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">using</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ui</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">new</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">firebaseui</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">AuthUI</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">();</span> </code></pre></devsite-code> </li> </ol> <h3 is-upgraded id="add-an-rsvp-button-to-the-html" data-text="Add an RSVP button to the HTML" tabindex="-1">Add an RSVP button to the HTML</h3> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.html</code> file.</li> <li>Add the HTML for an RSVP button inside the <code translate="no" dir="ltr">event-details-container</code> as shown in the example below. <br><br> Be careful to use the same <code translate="no" dir="ltr">id</code> values as shown below because, for this codelab, there are already hooks for these specific IDs in the <code translate="no" dir="ltr">index.js</code> file. <br><br> Note that in the <code translate="no" dir="ltr">index.html</code> file, there&#39;s a container with the ID <code translate="no" dir="ltr">firebaseui-auth-container</code>. This is the ID that you&#39;ll pass to FirebaseUI to hold your login.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-html" class="language-html" translate="no" dir="ltr">&lt;!-- ... --&gt; &lt;section id="event-details-container"&gt; &lt;!-- ... --&gt; &lt;!-- ADD THE RSVP BUTTON HERE --&gt; &lt;button id="startRsvp"&gt;RSVP&lt;/button&gt; &lt;/section&gt; &lt;hr&gt; &lt;section id="firebaseui-auth-container"&gt;&lt;/section&gt; &lt;!-- ... --&gt; </code></pre></devsite-code> <strong>App preview<br><br></strong><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/ab9ad7d61bb7b28c_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Set up a listener on the RSVP button and call the FirebaseUI start function. This tells FirebaseUI that you want to see the sign-in window. <br><br> Add the following code to the bottom of the <code translate="no" dir="ltr">main()</code> function in <code translate="no" dir="ltr">index.js</code>:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-js" class="language-js" translate="no" dir="ltr">async function main() { // ... // Listen to RSVP button clicks startRsvpButton.addEventListener("click", () =&gt; { ui.start("#firebaseui-auth-container", uiConfig); }); } main(); </code></pre></devsite-code> </li> </ol> <h2 is-upgraded id="test-signing-in-to-the-app" data-text="Test signing in to the app" tabindex="-1"><strong>Test signing in to the app</strong></h2> <ol type="1"> <li>In StackBlitz&#39;s preview window, click the RSVP button to sign in to the app.<ul> <li>For this codelab, you can use any email address, even a fake email address, since you&#39;re not setting up an email verification step for this codelab.</li> <li>If you see an error message stating <code translate="no" dir="ltr">auth/operation-not-allowed</code> or <code translate="no" dir="ltr">The given sign-in provider is disabled for this Firebase project</code>, check to make sure that you enabled <strong>Email/Password</strong> as a sign-in provider in the Firebase console.</li> </ul> <strong>App preview<br><br></strong><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3024f90b52ad55fe_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> <li>Go to the <a href="https://console.firebase.google.com/u/0/project/_/authentication/users" target="_blank"><strong>Authentication</strong> dashboard</a> in the Firebase console. In the <strong>Users</strong> tab, you should see the account information that you entered to sign in to the app.<br><br><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/682fc0eca86a99fc_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></li> </ol> <aside class="special"><p><strong>Tip</strong>: Check out the <a href="https://firebase.google.com/docs/auth/web/firebaseui" target="_blank">Firebase documentation</a> to learn how to use FirebaseUI and Firebase Authentication to add social sign-in providers (such as GitHub, Google, and Facebook) to your app.</p> </aside> <h2 is-upgraded id="add-authentication-state-to-the-ui" data-text="Add authentication state to the UI" tabindex="-1"><strong>Add authentication state to the UI</strong></h2> <p>Next, make sure that the UI reflects the fact that you&#39;re signed in.</p> <p>You&#39;ll use the Firebase Authentication state listener callback, which gets notified whenever the user&#39;s sign-in status changes. If there&#39;s currently a signed-in user, your app will switch the &#34;RSVP&#34; button to a &#34;logout&#34; button.</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>At the top, locate the <code translate="no" dir="ltr">firebase/auth</code> import statement, then add <code translate="no" dir="ltr">signOut</code> and <code translate="no" dir="ltr">onAuthStateChanged</code>, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span> <span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Add</span> <span class="devsite-syntax-n">the</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">products</span> <span class="devsite-syntax-ow">and</span> <span class="devsite-syntax-n">methods</span> <span class="devsite-syntax-n">that</span> <span class="devsite-syntax-n">you</span> <span class="devsite-syntax-n">want</span> <span class="devsite-syntax-n">to</span> <span class="devsite-syntax-n">use</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">getAuth</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">EmailAuthProvider</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">signOut</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">onAuthStateChanged</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/auth'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/firestore'</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> </li> <li>Add the following code at the bottom of the <code translate="no" dir="ltr">main()</code> function:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-js" class="language-js" translate="no" dir="ltr">async function main() { // ... // Listen to the current Auth state onAuthStateChanged(auth, user =&gt; { if (user) { startRsvpButton.textContent = 'LOGOUT'; } else { startRsvpButton.textContent = 'RSVP'; } }); } main(); </code></pre></devsite-code> </li> <li>In the button listener, check whether there is a current user and log them out. To do this, <strong><em>replace the current </em></strong><code translate="no" dir="ltr">startRsvpButton.addEventListener</code> with the following:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-c1">// Called when the user clicks the RSVP button</span> <span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">addEventListener</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'click'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">currentUser</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// User is signed in; allows user to sign out</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">signOut</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// No user is signed in; allows user to sign in</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ui</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">start</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'#firebaseui-auth-container'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">uiConfig</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">});</span> </code></pre></devsite-code> </li> </ol> <p>Now, the button in your app should show <strong>LOGOUT</strong>, and it should switch back to <strong>RSVP</strong> when it&#39;s clicked.</p> <h3 is-upgraded id="app-preview_1" data-text="App preview" tabindex="-1">App preview</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4c540450924f1607_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <aside class="warning"><p>Are you stuck or think that you might be off track? Here&#39;s a StackBlitz link that&#39;s updated with all of the code added up to this point of the codelab: <a href="https://stackblitz.com/edit/firebase-gtk-web-checkpoint1" target="_blank">https://stackblitz.com/edit/firebase-gtk-web-checkpoint1</a></p> <p>Make sure that you do two things at this checkpoint:</p> <ol type="1"> <li>Fork the project so that it&#39;s your own.</li> <li>Add your Firebase project configuration object from the Firebase console.</li> </ol> </aside> </google-codelab-step> <google-codelab-step label="Write messages to Cloud Firestore" duration="10" step="6"> <h2 class="step-title" id="6" data-text="Write messages to Cloud Firestore" tabindex="-1"> 7. Write messages to Cloud Firestore </h2> <p>Knowing that users are coming is great, but let&#39;s give the guests something else to do in the app. What if they could leave messages in a guestbook? They can share why they&#39;re excited to come or who they hope to meet.</p> <p>To store the chat messages that users write in the app, you&#39;ll use <a href="https://firebase.google.com/docs/firestore/" target="_blank">Cloud Firestore</a>.</p> <h2 is-upgraded id="data-model" data-text="Data model" tabindex="-1"><strong>Data model</strong></h2> <p>Cloud Firestore is a NoSQL database, and data stored in the database is split into collections, documents, fields, and subcollections. You will store each message of the chat as a document in a top-level collection called <code translate="no" dir="ltr">guestbook</code>.</p> <p class="image-container"><img alt="Firestore data model graphic showing a guestbook collection with multiple message documents" style="width: 249.32px" src="/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/b447950f9f993789_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <aside class="special"><p><strong>Tip</strong>: To learn more about the Cloud Firestore data model, read about documents and collections in <a href="https://firebase.google.com/docs/firestore/data-model" target="_blank">the Cloud Firestore documentation</a>. You can also watch a <a href="https://www.youtube.com/playlist?list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ" target="_blank">great series of videos</a> that describe the Cloud Firestore NoSQL data model, queries, and other cool things that you can do with Cloud Firestore.</p> </aside> <h2 is-upgraded id="add-messages-to-firestore" data-text="Add messages to Firestore" tabindex="-1"><strong>Add messages to Firestore</strong></h2> <p>In this section, you&#39;ll add the functionality for users to write new messages to the database. First, you add the HTML for the UI elements (message field and send button). Then, you add the code that hooks these elements up to the database.</p> <p>To add the UI elements of a message field and a send button:</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.html</code> file.</li> <li>Locate the <code translate="no" dir="ltr">guestbook-container</code>, then add the following HTML to create a form with the message input field and the send button.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Carbon"><code language="language-html" class="language-html" translate="no" dir="ltr">&lt;<span class="devsite-syntax-p">!</span><span class="devsite-syntax-o">--</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">--</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">section</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">id</span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-s">"guestbook-container"</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">h2&gt;Discussion</span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">h2</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">form</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">id</span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-s">"leave-message"</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">label&gt;Leave</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">a</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">message</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">label</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">input</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">type</span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-s">"text"</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">id</span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-s">"message"</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">button</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">type</span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-s">"submit"</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">i</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">class</span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-s">"material-icons"</span>&gt;<span class="devsite-syntax-nx">send</span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">i</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-nx">span&gt;SEND</span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">span</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">button</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">form</span>&gt; <span class="devsite-syntax-w"> </span>&lt;<span class="devsite-syntax-o">/</span><span class="devsite-syntax-nx">section</span>&gt; &lt;<span class="devsite-syntax-p">!</span><span class="devsite-syntax-o">--</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">--</span>&gt; </code></pre></devsite-code> </li> </ol> <h3 is-upgraded id="app-preview_2" data-text="App preview" tabindex="-1">App preview</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/4a892284443cf73d_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <p>A user clicking the <strong>SEND</strong> button will trigger the code snippet below. It adds the contents of the message input field to the <code translate="no" dir="ltr">guestbook</code> collection of the database. Specifically, the <code translate="no" dir="ltr">addDoc</code> method adds the message content to a new document (with an automatically generated ID) to the <code translate="no" dir="ltr">guestbook</code> collection.</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>At the top, locate the <code translate="no" dir="ltr">firebase/firestore</code> import statement, then add <code translate="no" dir="ltr">getFirestore</code>, <code translate="no" dir="ltr">addDoc</code>, and <code translate="no" dir="ltr">collection</code>, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span> <span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Add</span> <span class="devsite-syntax-n">the</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">products</span> <span class="devsite-syntax-ow">and</span> <span class="devsite-syntax-n">methods</span> <span class="devsite-syntax-n">that</span> <span class="devsite-syntax-n">you</span> <span class="devsite-syntax-n">want</span> <span class="devsite-syntax-n">to</span> <span class="devsite-syntax-n">use</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">getAuth</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">EmailAuthProvider</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">signOut</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">onAuthStateChanged</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/auth'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">getFirestore</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">addDoc</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">collection</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/firestore'</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> </li> <li>Now we&#39;ll save a reference to the Firestore <code translate="no" dir="ltr">db</code> object right after <code translate="no" dir="ltr">initializeApp</code>:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-js" class="language-js" translate="no" dir="ltr">initializeApp(firebaseConfig); auth = getAuth(); db = getFirestore(); </code></pre></devsite-code> </li> <li>At the bottom of the <code translate="no" dir="ltr">main()</code> function, add the following code. <br><br> Note that <code translate="no" dir="ltr">auth.currentUser.uid</code> is a reference to the auto-generated unique ID that Firebase Authentication gives for all logged-in users.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="CSS+Lasso"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-nt">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">main</span><span class="devsite-syntax-o">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">Listen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">form</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">submission</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">form.addEventListener('submit',</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">e</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">Prevent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">default</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">form</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">redirect</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">e.preventDefault()</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">Write</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">a</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">new</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">message</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">database</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">collection</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">"guestbook"</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">addDoc(collection(db,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">'guestbook'),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">input</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">timestamp</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Date</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-nf">now</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">name</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">currentUser</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">displayName</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">userId</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">currentUser</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-o">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">clear</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">message</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">input</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">field</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">input</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nc">value</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">''</span><span class="devsite-syntax-o">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">Return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">false</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">avoid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">redirect</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">false</span><span class="devsite-syntax-o">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">}</span><span class="devsite-syntax-o">);</span> <span class="devsite-syntax-err">}</span> <span class="devsite-syntax-nt">main</span><span class="devsite-syntax-o">();</span> </code></pre></devsite-code> </li> </ol> <h2 is-upgraded id="show-the-guestbook-only-to-signed-in-users" data-text="Show the guestbook only to signed-in users" tabindex="-1"><strong>Show the guestbook only to signed-in users</strong></h2> <p>You don&#39;t want just <em>anybody</em> to see the guests&#39; chat. One thing that you can do to secure the chat is to allow only signed-in users to view the guestbook. That said, for your own apps, you&#39;ll want to also secure your database with <a href="https://firebase.google.com/docs/rules" target="_blank">Firebase Security Rules</a>. (There&#39;s more information on security rules later in the codelab.)</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>Edit the <code translate="no" dir="ltr">onAuthStateChanged</code> listener to hide and show the guestbook.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-c1">// Listen to the current Auth state</span> <span class="devsite-syntax-n">onAuthStateChanged</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'LOGOUT'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Show guestbook to logged-in users</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookContainer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">display</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'block'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'RSVP'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Hide guestbook for non-logged-in users</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookContainer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">display</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'none'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">});</span> </code></pre></devsite-code> </li> </ol> <h2 is-upgraded id="test-sending-messages" data-text="Test sending messages" tabindex="-1"><strong>Test sending messages</strong></h2> <ol type="1"> <li>Make sure that you&#39;re signed in to the app.</li> <li>Enter a message such as &#34;Hey there!&#34;, then click <strong>SEND</strong>.</li> </ol> <p>This action writes the message to your Cloud Firestore database. However, you won&#39;t yet see the message in your actual web app because you still need to implement retrieving the data. You&#39;ll do that next.</p> <p>But you can see the newly added message in the Firebase console.</p> <p>In the Firebase console, in the <a href="https://console.firebase.google.com/project/_/firestore" target="_blank"><strong>Firestore Database</strong> dashboard</a>, you should see the <code translate="no" dir="ltr">guestbook</code> collection with your newly added message. If you keep sending messages, your guestbook collection will contain many documents, like this:</p> <h3 is-upgraded id="firebase-console" data-text="Firebase console" tabindex="-1">Firebase console</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/713870af0b3b63c_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <aside class="warning"><p>Are you stuck or think that you might be off track? Here&#39;s a StackBlitz link that&#39;s updated with all of the code added up to this point of the codelab: <a href="https://stackblitz.com/edit/firebase-gtk-web-checkpoint2" target="_blank">https://stackblitz.com/edit/firebase-gtk-web-checkpoint2</a></p> <p>Make sure that you do two things at this checkpoint:</p> <ol type="1"> <li>Fork the project so that it&#39;s your own.</li> <li>Add your Firebase project configuration object from the Firebase console.</li> </ol> </aside> </google-codelab-step> <google-codelab-step label="Read messages" duration="10" step="7"> <h2 class="step-title" id="7" data-text="Read messages" tabindex="-1"> 8. Read messages </h2> <h2 is-upgraded id="synchronize-messages" data-text="Synchronize messages" tabindex="-1"><strong>Synchronize messages</strong></h2> <p>It&#39;s lovely that guests can write messages to the database, but they can&#39;t see them in the app yet.</p> <p>To display messages, you&#39;ll need to add listeners that trigger when data changes, then create a UI element that shows new messages.</p> <p>You&#39;ll add code that listens for newly added messages from the app. First, add a section in the HTML to show messages:</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.html</code> file.</li> <li>In <code translate="no" dir="ltr">guestbook-container</code>, add a new section with the ID of <code translate="no" dir="ltr">guestbook</code>.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-html" class="language-html" translate="no" dir="ltr">&lt;!-- ... --&gt; &lt;section id="guestbook-container"&gt; &lt;h2&gt;Discussion&lt;/h2&gt; &lt;form&gt;&lt;!-- ... --&gt;&lt;/form&gt; &lt;section id="guestbook"&gt;&lt;/section&gt; &lt;/section&gt; &lt;!-- ... --&gt; </code></pre></devsite-code> </li> </ol> <p>Next, register the listener that listens for changes made to the data:</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>At the top, locate the <code translate="no" dir="ltr">firebase/firestore</code> import statement, then add <code translate="no" dir="ltr">query</code>, <code translate="no" dir="ltr">orderBy</code>, and <code translate="no" dir="ltr">onSnapshot</code>, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span> <span class="devsite-syntax-o">...</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">getFirestore</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">addDoc</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">collection</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">query</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">orderBy</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">onSnapshot</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/firestore'</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> </li> <li>At the bottom of the <code translate="no" dir="ltr">main()</code> function, add the following code to loop through all the documents (guestbook messages) in the database. To learn more about what&#39;s happening in this code, read the information below the snippet.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-n">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Create</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">query</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">messages</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">q</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">query</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">collection</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">db</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'guestbook'</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">orderBy</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'timestamp'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'desc'</span><span class="devsite-syntax-p">));</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onSnapshot</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">q</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">snaps</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Reset</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbook</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">innerHTML</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">''</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Loop</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">through</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">documents</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">database</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">snaps</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">forEach</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Create</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">an</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">HTML</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">each</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">and</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">it</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">chat</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">createElement</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'p'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">name</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">+</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">': '</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">+</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbook</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">appendChild</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">();</span> </code></pre></devsite-code> </li> </ol> <p>To listen to messages in the database, you&#39;ve created a query on a specific collection by using the <code translate="no" dir="ltr">collection</code> function. The code above listens to the changes in the <code translate="no" dir="ltr">guestbook</code> collection, which is where the chat messages are stored. The messages are also ordered by date, using <code translate="no" dir="ltr">orderBy('timestamp', 'desc')</code> to display the newest messages at the top.</p> <p>The <code translate="no" dir="ltr">onSnapshot</code> function takes two parameters: the query to use and a callback function. The callback function is triggered when there are any changes to documents that match the query. This could be if a message gets deleted, modified, or added. For more information, see the <a href="https://firebase.google.com/docs/firestore/query-data/listen" target="_blank">Cloud Firestore documentation</a>.</p> <aside class="special"><p><strong>Tip</strong>: For a faster refresh, you can update only the changed documents, instead of the whole list. Learn more in the <a href="https://firebase.google.com/docs/firestore/query-data/listen#view_changes_between_snapshots" target="_blank">Cloud Firestore documentation</a>.</p> </aside> <h2 is-upgraded id="test-synchronizing-messages" data-text="Test synchronizing messages" tabindex="-1"><strong>Test synchronizing messages</strong></h2> <p>Cloud Firestore automatically and instantly synchronizes data with clients subscribed to the database.</p> <ul> <li>The messages that you created earlier in the database should be displayed in the app. Feel free to write new messages; they should appear instantly.</li> <li>If you open your workspace in multiple windows or tabs, messages will sync in real time across tabs.</li> <li><em>(Optional)</em> You can try manually deleting, modifying, or adding new messages directly in the <strong>Database</strong> section of the Firebase console; any changes should appear in the UI.</li> </ul> <p>Congratulations! You&#39;re reading Cloud Firestore documents in your app!</p> <h3 is-upgraded id="app-preview_3" data-text="App preview" tabindex="-1">App preview</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/e30df0a9614bae7d_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <aside class="warning"><p>Are you stuck or think that you might be off track? Here&#39;s a StackBlitz link that&#39;s updated with all of the code added up to this point of the codelab: <a href="https://stackblitz.com/edit/firebase-gtk-web-checkpoint3" target="_blank">https://stackblitz.com/edit/firebase-gtk-web-checkpoint3</a></p> <p>Make sure that you do two things at this checkpoint:</p> <ol type="1"> <li>Fork the project so that it&#39;s your own.</li> <li>Add your Firebase project configuration object from the Firebase console.</li> </ol> </aside> </google-codelab-step> <google-codelab-step label="Set up basic security rules" duration="5" step="8"> <h2 class="step-title" id="8" data-text="Set up basic security rules" tabindex="-1"> 9. Set up basic security rules </h2> <p>You initially set up Cloud Firestore to use test mode, meaning that your database is open for reads and writes. However, you should only use test mode during very early stages of development. As a best practice, you should set up security rules for your database as you develop your app. Security should be integral to your app&#39;s structure and behavior.</p> <p>Security Rules allow you to control access to documents and collections in your database. The flexible rules syntax allows you to create rules that match anything from all writes to the entire database to operations on a specific document.</p> <p>You can write security rules for Cloud Firestore in the Firebase console:</p> <ol type="1"> <li>In the Firebase console&#39;s <strong>Build</strong> section, click <strong>Firestore Database</strong>, then select the <strong>Rules</strong> tab (or <a href="https://console.firebase.google.com/project/_/firestore/rules" target="_blank">click here</a> to go directly to the <strong>Rules</strong> tab).</li> <li>You should see the following default security rules, with a public-access time limit a couple of weeks from today.</li> </ol> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/7767a2d2e64e7275_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <aside class="special"><p>Check out the <a href="https://firebase.google.com/docs/rules" target="_blank">Firebase Security Rules documentation</a> or this <a href="https://www.youtube.com/watch?v=QEuu9X9L-MU&list=PLl-K7zZEsYLn8h1NyU_OV6dX8mBhH2s_L" target="_blank">YouTube playlist</a> to learn more about security rules.</p> </aside> <h2 is-upgraded id="identify-collections" data-text="Identify collections" tabindex="-1"><strong>Identify collections</strong></h2> <p>First, identify the collections to which the app writes data.</p> <ol type="1"> <li>Delete the existing <code translate="no" dir="ltr">match /{document=**}</code> clause, so your rules look like this:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="scdoc"><code translate="no" dir="ltr">rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { } } </code></pre></devsite-code> </li> <li>In <code translate="no" dir="ltr">match /databases/{database}/documents</code>, identify the collection that you want to secure:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="scdoc"><code translate="no" dir="ltr">rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { // You'll add rules here in the next step. } } </code></pre></devsite-code> </li> </ol> <h2 is-upgraded id="add-security-rules" data-text="Add security rules" tabindex="-1"><strong>Add security rules</strong></h2> <p>Because you used the Authentication UID as a field in each guestbook document, you can get the Authentication UID and verify that anyone attempting to write to the document has a matching Authentication UID.</p> <ol type="1"> <li>Add the read and write rules to your rule set as shown below:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="CSS+Lasso"><code translate="no" dir="ltr"><span class="devsite-syntax-nt">rules_version</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'2'</span><span class="devsite-syntax-o">;</span> <span class="devsite-syntax-nt">service</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">cloud</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nc">firestore</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/databases/{database</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-o">/</span><span class="devsite-syntax-nt">documents</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/guestbook/{entry</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">read</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">!=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">null</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">create</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">==</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">resource</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">userId</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">}</span> <span class="devsite-syntax-err">}</span> </code></pre></devsite-code> </li> <li>Click <strong>Publish</strong> to deploy your new rules.Now, for the guestbook, only signed-in users can read messages (any message!), but you can only create a message using your user ID. We also don&#39;t allow messages to be edited or deleted.</li> </ol> <h2 is-upgraded id="add-validation-rules" data-text="Add validation rules" tabindex="-1"><strong>Add validation rules</strong></h2> <ol type="1"> <li>Add data validation to make sure that all of the expected fields are present in the document:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="CSS+Lasso"><code translate="no" dir="ltr"><span class="devsite-syntax-nt">rules_version</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'2'</span><span class="devsite-syntax-o">;</span> <span class="devsite-syntax-nt">service</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">cloud</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nc">firestore</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/databases/{database</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-o">/</span><span class="devsite-syntax-nt">documents</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/guestbook/{entry</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">read</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">!=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">null</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">create</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">==</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">resource</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">userId</span> <span class="devsite-syntax-w"> &amp;&amp; </span><span class="devsite-syntax-s2">"name"</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">resource</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span> <span class="devsite-syntax-w"> &amp;&amp; </span><span class="devsite-syntax-s2">"text"</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">resource</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span> <span class="devsite-syntax-w"> &amp;&amp; </span><span class="devsite-syntax-s2">"timestamp"</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">resource</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">}</span> <span class="devsite-syntax-err">}</span> </code></pre></devsite-code> </li> <li>Click <strong>Publish</strong> to deploy your new rules.</li> </ol> <h2 is-upgraded id="reset-listeners" data-text="Reset listeners" tabindex="-1"><strong>Reset listeners</strong></h2> <p>Because your app now only allows authenticated users to log in, you should move the guestbook <code translate="no" dir="ltr">firestore</code> query inside the Authentication listener. Otherwise, permission errors will occur and the app will be disconnected when the user logs out.</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>Pull the guestbook collection <code translate="no" dir="ltr">onSnapshot</code> listener into a new function called <code translate="no" dir="ltr">subscribeGuestbook</code>. Also, assign the results of the <code translate="no" dir="ltr">onSnapshot</code> function to the <code translate="no" dir="ltr">guestbookListener</code> variable. <br><br> The Firestore <code translate="no" dir="ltr">onSnapshot</code> listener <a href="https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference.html#returns-function" target="_blank">returns</a> an unsubscribe function that you&#39;ll be able to use to cancel the snapshot listener later.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Listen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbook</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">updates</span> <span class="devsite-syntax-n">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">subscribeGuestbook</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">q</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">query</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">collection</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">db</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'guestbook'</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">orderBy</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'timestamp'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'desc'</span><span class="devsite-syntax-p">));</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookListener</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onSnapshot</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">q</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">snaps</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Reset</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbook</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">innerHTML</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">''</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Loop</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">through</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">documents</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">database</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">snaps</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">forEach</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Create</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">an</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">HTML</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">each</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">and</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">it</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">chat</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">createElement</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'p'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">name</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">+</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">': '</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">+</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbook</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">appendChild</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">entry</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> </li> <li>Add a new function underneath called <code translate="no" dir="ltr">unsubscribeGuestbook</code>. Check whether the <code translate="no" dir="ltr">guestbookListener</code> variable is not null, then call the function to cancel the listener.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-c1">// Unsubscribe from guestbook updates</span> <span class="devsite-syntax-k">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nf">unsubscribeGuestbook</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">guestbookListener</span><span class="devsite-syntax-w"> </span>!<span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">null</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookListener</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookListener</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">null</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> </li> </ol> <p>Finally, add the new functions to the <code translate="no" dir="ltr">onAuthStateChanged</code> callback.</p> <ol type="1" start="4"> <li>Add <code translate="no" dir="ltr">subscribeGuestbook()</code> at the bottom of <code translate="no" dir="ltr">if (user)</code>.</li> <li>Add <code translate="no" dir="ltr">unsubscribeGuestbook()</code> at the bottom of the <code translate="no" dir="ltr">else</code> statement.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-c1">// Listen to the current Auth state</span> <span class="devsite-syntax-n">onAuthStateChanged</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'LOGOUT'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Show guestbook to logged-in users</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookContainer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">display</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'block'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Subscribe to the guestbook collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">subscribeGuestbook</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'RSVP'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Hide guestbook for non-logged-in users</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookContainer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">display</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'none'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Unsubscribe from the guestbook collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">unsubscribeGuestbook</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">});</span> </code></pre></devsite-code> </li> </ol> <aside class="warning"><p>Are you stuck or think that you might be off track? Here&#39;s a StackBlitz link that&#39;s updated with all of the code added up to this point of the codelab: <a href="https://stackblitz.com/edit/firebase-gtk-web-checkpoint4" target="_blank">https://stackblitz.com/edit/firebase-gtk-web-checkpoint4</a></p> <p>Make sure that you do two things at this checkpoint:</p> <ol type="1"> <li>Fork the project so that it&#39;s your own.</li> <li>Add your Firebase project configuration object from the Firebase console.</li> </ol> </aside> </google-codelab-step> <google-codelab-step label="Bonus step: Practice what you&#39;ve learned" duration="0" step="9"> <h2 class="step-title" id="9" data-text="Bonus step: Practice what you've learned" tabindex="-1"> 10. Bonus step: Practice what you've learned </h2> <h2 is-upgraded id="record-an-attendees-rsvp-status" data-text="Record an attendee's RSVP status" tabindex="-1"><strong>Record an attendee's RSVP status</strong></h2> <p>Right now, your app just allows people to start chatting if they&#39;re interested in the event. Also, the only way you know if someone&#39;s coming is if they post it in the chat. Let&#39;s get organized and let people know how many people are coming.</p> <p>You&#39;ll add a toggle to register people who want to attend the event, then collect a count of how many people are coming.</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.html</code> file.</li> <li>In <code translate="no" dir="ltr">guestbook-container</code>, add a set of <strong>YES</strong> and <strong>NO</strong> buttons, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-html" class="language-html" translate="no" dir="ltr">&lt;!-- ... --&gt; &lt;section id="guestbook-container"&gt; &lt;h2&gt;Are you attending?&lt;/h2&gt; &lt;button id="rsvp-yes"&gt;YES&lt;/button&gt; &lt;button id="rsvp-no"&gt;NO&lt;/button&gt; &lt;h2&gt;Discussion&lt;/h2&gt; &lt;!-- ... --&gt; &lt;/section&gt; &lt;!-- ... --&gt; </code></pre></devsite-code> </li> </ol> <h3 is-upgraded id="app-preview_4" data-text="App preview" tabindex="-1">App preview</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/73ca99ca35c13ee7_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <p>Next, register the listener for button clicks. If the user clicks <strong>YES</strong>, then use their Authentication UID to save the response to the database.</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>At the top, locate the <code translate="no" dir="ltr">firebase/firestore</code> import statement, then add <code translate="no" dir="ltr">doc</code>, <code translate="no" dir="ltr">setDoc</code>, and <code translate="no" dir="ltr">where</code>, like so:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span> <span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Add</span> <span class="devsite-syntax-n">the</span> <span class="devsite-syntax-n">Firebase</span> <span class="devsite-syntax-n">products</span> <span class="devsite-syntax-ow">and</span> <span class="devsite-syntax-n">methods</span> <span class="devsite-syntax-n">that</span> <span class="devsite-syntax-n">you</span> <span class="devsite-syntax-n">want</span> <span class="devsite-syntax-n">to</span> <span class="devsite-syntax-n">use</span> <span class="devsite-syntax-kn">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">getFirestore</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">addDoc</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">collection</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">query</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">orderBy</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">onSnapshot</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">doc</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">setDoc</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">where</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-kn">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'firebase/firestore'</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> </li> <li>At the bottom of the <code translate="no" dir="ltr">main()</code> function, add the following code to listen to the RSVP status:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-js" class="language-js" translate="no" dir="ltr">async function main() { // ... // Listen to RSVP responses rsvpYes.onclick = async () =&gt; { }; rsvpNo.onclick = async () =&gt; { }; } main(); </code></pre></devsite-code> </li> <li>Next, create a new collection called <code translate="no" dir="ltr">attendees</code>, then register a document reference if either RSVP button is clicked. Set that reference to <code translate="no" dir="ltr">true</code> or <code translate="no" dir="ltr">false</code> depending on which button is clicked. <br><br> First, for <code translate="no" dir="ltr">rsvpYes</code>:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Listen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">RSVP</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">responses</span> <span class="devsite-syntax-n">rsvpYes</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">onclick</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Get</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">a</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">reference</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">user</span><span class="devsite-syntax-s1">'s document in the attendees collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">userRef</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">db</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'attendees'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">currentUser</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">If</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">they</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">RSVP</span><span class="devsite-syntax-s1">'d yes, save a document with attendi()ng: true</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">try</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">setDoc</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">userRef</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">attending</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">true</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">catch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">e</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">console</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">error</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">e</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">};</span> </code></pre></devsite-code> Then, the same for <code translate="no" dir="ltr">rsvpNo</code>, but with the value <code translate="no" dir="ltr">false</code>:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-n">rsvpNo</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">onclick</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Get</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">a</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">reference</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">user</span><span class="devsite-syntax-s1">'s document in the attendees collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">userRef</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">db</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'attendees'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">currentUser</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">If</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">they</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">RSVP</span><span class="devsite-syntax-s1">'d yes, save a document with attending: true</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">try</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">await</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">setDoc</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">userRef</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">attending</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">false</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">catch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">e</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">console</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">error</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">e</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">};</span> </code></pre></devsite-code> </li> </ol> <h2 is-upgraded id="update-your-security-rules" data-text="Update your Security Rules" tabindex="-1"><strong>Update your Security Rules</strong></h2> <p>Because you already have some rules set up, the new data that you&#39;re adding with the buttons is going to be rejected.</p> <h3 is-upgraded id="allow-additions-to-the-attendees-collection" data-text="Allow additions to the attendees collection" tabindex="-1"><strong>Allow additions to the </strong><strong><code translate="no" dir="ltr">attendees</code></strong><strong> collection</strong></h3> <p>You&#39;ll need to update the rules to allow adding to the <code translate="no" dir="ltr">attendees</code> collection.</p> <ol type="1"> <li>For the <code translate="no" dir="ltr">attendees</code> collection, since you used the Authentication UID as the document name, you can grab it and verify that the submitter&#39;s <code translate="no" dir="ltr">uid</code> is the same as the document they are writing. You&#39;ll allow everyone to read the attendees list (since there is no private data there), but only the creator should be able to update it.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="CSS+Lasso"><code translate="no" dir="ltr"><span class="devsite-syntax-nt">rules_version</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'2'</span><span class="devsite-syntax-o">;</span> <span class="devsite-syntax-nt">service</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">cloud</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nc">firestore</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/databases/{database</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-o">/</span><span class="devsite-syntax-nt">documents</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">...</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/attendees/{userId</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">read</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">true</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">write</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">==</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">userId</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">}</span> <span class="devsite-syntax-err">}</span> </code></pre></devsite-code> </li> <li>Click <strong>Publish</strong> to deploy your new rules.</li> </ol> <h3 is-upgraded id="add-validation-rules_1" data-text="Add validation rules" tabindex="-1"><strong>Add validation rules</strong></h3> <ol type="1"> <li>Add some data validation rules to make sure that all of the expected fields are present in the document:<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="CSS+Lasso"><code translate="no" dir="ltr"><span class="devsite-syntax-nt">rules_version</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'2'</span><span class="devsite-syntax-o">;</span> <span class="devsite-syntax-nt">service</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nt">cloud</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nc">firestore</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/databases/{database</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-o">/</span><span class="devsite-syntax-nt">documents</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">...</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">//</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">match</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">/attendees/{userId</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">read</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">true</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">allow</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">write</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">==</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">userId</span> <span class="devsite-syntax-w"> &amp;&amp; </span><span class="devsite-syntax-s2">"attending"</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">request</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">resource</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">}</span> <span class="devsite-syntax-err">}</span> </code></pre></devsite-code> </li> <li>Don&#39;t forget to click <strong>Publish</strong> to deploy your rules! <br></li> </ol> <p><em>(Optional)</em> You can now view the results of clicking the buttons. Go to your Cloud Firestore dashboard in the Firebase console.</p> <h2 is-upgraded id="read-rsvp-status" data-text="Read RSVP status" tabindex="-1"><strong>Read RSVP status</strong></h2> <p>Now that you&#39;ve recorded the responses, let&#39;s see who&#39;s coming and reflect it in the UI.</p> <ol type="1"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.html</code> file.</li> <li>In <code translate="no" dir="ltr">description-container</code>, add a new element with the ID of <code translate="no" dir="ltr">number-attending</code>.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code language="language-html" class="language-html" translate="no" dir="ltr">&lt;!-- ... --&gt; &lt;section id="description-container"&gt; &lt;!-- ... --&gt; &lt;p id="number-attending"&gt;&lt;/p&gt; &lt;/section&gt; &lt;!-- ... --&gt; </code></pre></devsite-code> </li> </ol> <p>Next, register the listener for the <code translate="no" dir="ltr">attendees</code> collection and count the number of <strong>YES</strong> responses:</p> <ol type="1" start="3"> <li>In StackBlitz, go to the <code translate="no" dir="ltr">index.js</code> file.</li> <li>At the bottom of the <code translate="no" dir="ltr">main()</code> function, add the following code to listen to the RSVP status and count <strong>YES</strong> clicks.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-n">async</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Listen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">attendee</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">list</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">attendingQuery</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">query</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">collection</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">db</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'attendees'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">where</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'attending'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'=='</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">true</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">unsubscribe</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onSnapshot</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">attendingQuery</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">snap</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">newAttendeeCount</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">snap</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">docs</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">length</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">numberAttending</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">innerHTML</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">newAttendeeCount</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">+</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">' people going'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">();</span> </code></pre></devsite-code> </li> </ol> <p>Finally, let&#39;s highlight the button corresponding to the current status.</p> <ol type="1" start="5"> <li>Create a function that checks whether the current Authentication UID has an entry in the <code translate="no" dir="ltr">attendees</code> collection, then set the button class to <code translate="no" dir="ltr">clicked</code>.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Listen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">attendee</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">list</span> <span class="devsite-syntax-n">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">subscribeCurrentRSVP</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">user</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ref</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">db</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'attendees'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">user</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">uid</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpListener</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onSnapshot</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">ref</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-w"> &amp;&amp; </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">())</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">attendingResponse</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">doc</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">data</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">attending</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Update</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">css</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">classes</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">buttons</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">attendingResponse</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpYes</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">className</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'clicked'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpNo</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">className</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">''</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpYes</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">className</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">''</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpNo</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">className</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'clicked'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> </li> <li>Also, let&#39;s make a function to unsubscribe. This will be used when the user logs out.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-k">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nf">unsubscribeCurrentRSVP</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">rsvpListener</span><span class="devsite-syntax-w"> </span>!<span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">null</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpListener</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpListener</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">null</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpYes</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">className</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">''</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rsvpNo</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">className</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">''</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> </li> <li>Call the functions from the Authentication listener.<div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code language="language-js" class="language-js" translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-c1">// Listen to the current Auth state</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Listen to the current Auth state</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onAuthStateChanged</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">auth</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'LOGOUT'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Show guestbook to logged-in users</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookContainer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">display</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'block'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Subscribe to the guestbook collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">subscribeGuestbook</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Subscribe to the user's RSVP</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">subscribeCurrentRSVP</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb">user</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">startRsvpButton</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">textContent</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'RSVP'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Hide guestbook for non-logged-in users</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">guestbookContainer</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">display</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">'none'</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Unsubscribe from the guestbook collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">unsubscribeGuestbook</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Unsubscribe from the guestbook collection</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">unsubscribeCurrentRSVP</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> </code></pre></devsite-code> </li> <li>Try logging in as multiple users and see the count increase with each additional <strong>YES</strong> button click.</li> </ol> <h3 is-upgraded id="app-preview_5" data-text="App preview" tabindex="-1">App preview</h3> <p class="image-container"><img alt="screenshot of this step" style="width: 624.00px" src="/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35.png" srcset="https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_36.png 36w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_48.png 48w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_72.png 72w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_96.png 96w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_480.png 480w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_720.png 720w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_856.png 856w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_960.png 960w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_1440.png 1440w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_1920.png 1920w,https://firebase.google.com/static/codelabs/firebase-get-to-know-web/img/3df607d3e0b3c35_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"><br><br></p> <aside class="warning"><p>Are you stuck or think that you might be off track? Here&#39;s a StackBlitz link that&#39;s updated with all of the code added up to this point of the codelab: <a href="https://stackblitz.com/edit/firebase-gtk-web-checkpoint5" target="_blank">https://stackblitz.com/edit/firebase-gtk-web-checkpoint5</a></p> <p>Make sure that you do two things at this checkpoint:</p> <ol type="1"> <li>Fork the project so that it&#39;s your own.</li> <li>Add your Firebase project configuration object from the Firebase console.</li> </ol> </aside> </google-codelab-step> <google-codelab-step label="Congratulations!" duration="0" step="10"> <h2 class="step-title" id="10" data-text="Congratulations!" tabindex="-1"> 11. Congratulations! </h2> <p>You&#39;ve used Firebase to build an interactive, real-time web application!</p> <h2 class="checklist" is-upgraded id="what-weve-covered" data-text="What we've covered" tabindex="-1"><strong>What we've covered</strong></h2> <ul class="checklist"> <li>Firebase Authentication</li> <li>FirebaseUI</li> <li>Cloud Firestore</li> <li>Firebase Security Rules</li> </ul> <h2 is-upgraded id="next-steps" data-text="Next steps" tabindex="-1">Next steps</h2> <ul> <li><strong>Want to learn more the Firebase Developer Workflow?</strong> Check out the <a href="https://firebase.google.com/codelabs/firebase-emulator#0" target="_blank"><strong>Firebase emulator codelab</strong></a> to learn about how to test and run your app completely locally.</li> <li><strong>Want to learn more about other Firebase products?</strong> Maybe you want to store image files that users upload? Or send notifications to your users? Check out the <a href="https://firebase.google.com/codelabs/firebase-web#0" target="_blank"><strong>Firebase web codelab</strong></a> for a codelab that goes into more depth on many more Firebase products for web.</li> <li><strong>Want to learn more about Cloud Firestore?</strong> Maybe you want to learn about subcollections and transactions? Head over to the <a href="https://firebase.google.com/codelabs/firestore-web#0" target="_blank"><strong>Cloud Firestore web codelab</strong></a> for a codelab that goes into more depth on Cloud Firestore. Or check out this <a href="https://www.youtube.com/watch?v=v_hR4K4auoQ&list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ&index=2&t=0s" target="_blank"><strong>YouTube series to get to know Cloud Firestore</strong></a>! <devsite-youtube video-id="v_hR4K4auoQ"></devsite-youtube> </li> </ul> <h2 is-upgraded id="learn-more" data-text="Learn more" tabindex="-1"><strong>Learn more</strong></h2> <ul> <li>Firebase site: <a href="https://firebase.google.com" target="_blank">firebase.google.com</a></li> <li><a href="https://www.youtube.com/user/Firebase/featured" target="_blank">Firebase YouTube channel</a></li> </ul> <h2 is-upgraded id="how-did-it-go" data-text="How did it go?" tabindex="-1"><strong>How did it go?</strong></h2> <p>We would love your feedback! Please fill out a (very) short form <a href="https://forms.gle/53xm9Tva4TgA5Hg47" target="_blank">here</a>.</p> </google-codelab-step> </google-codelab> </div> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],[],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Learn</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="/docs/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Developer guides </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/docs/reference/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > SDK & API reference </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/docs/samples/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Samples </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/docs/libraries/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Libraries </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//github.com/firebase/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > GitHub </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Stay connected</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//firebase.blog" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Check out the blog </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.reddit.com/r/Firebase" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Find us on Reddit </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//x.com/Firebase" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Follow on X </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.youtube.com/user/Firebase" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Subscribe on YouTube </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/community/events" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Attend an event </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Support</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="/support/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Contact support </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//stackoverflow.com/questions/tagged/firebase" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Stack Overflow </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//firebase.community/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Slack community </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//groups.google.com/forum/#!forum/firebase-talk" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Google group </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/support/releases" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Release notes </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/brand-guidelines/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 6)" > Brand guidelines </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/support/faq/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 7)" > FAQs </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-sites" aria-label="Other Google Developers websites"> <a href="https://developers.google.com/" class="devsite-footer-sites-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Developers Link"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup-google-for-developers-dark-theme.svg" media="(prefers-color-scheme: none)" class="devsite-dark-theme" loading="lazy" alt="Google Developers"> <img class="devsite-footer-sites-logo" src="https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup-google-for-developers.svg" loading="lazy" alt="Google Developers"> </picture> </a> <ul class="devsite-footer-sites-list"> <li class="devsite-footer-sites-item"> <a href="//developer.android.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Android Link" > Android </a> </li> <li class="devsite-footer-sites-item"> <a href="//developer.chrome.com/home" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Chrome Link" > Chrome </a> </li> <li class="devsite-footer-sites-item"> <a href="//firebase.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Firebase Link" > Firebase </a> </li> <li class="devsite-footer-sites-item"> <a href="//cloud.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Cloud Platform Link" > Google Cloud Platform </a> </li> <li class="devsite-footer-sites-item"> <a href="//developers.google.com/products/" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer All products Link" > All products </a> </li> </ul> </nav> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="/terms/" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt" >Português</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> <devsite-concierge data-info-panel data-ai-panel > </devsite-concierge> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[]</script> <script type="application/json" tag-management>{&#34;at&#34;: &#34;True&#34;, &#34;ga4&#34;: [], &#34;ga4p&#34;: [], &#34;gtm&#34;: [{&#34;id&#34;: &#34;GTM-N84485&#34;, &#34;purpose&#34;: 0}], &#34;parameters&#34;: {&#34;internalUser&#34;: &#34;False&#34;, &#34;language&#34;: {&#34;machineTranslated&#34;: &#34;False&#34;, &#34;requested&#34;: &#34;en&#34;, &#34;served&#34;: &#34;en&#34;}, &#34;pageType&#34;: &#34;codelab&#34;, &#34;projectName&#34;: null, &#34;signedIn&#34;: &#34;False&#34;, &#34;tenant&#34;: &#34;firebase&#34;, &#34;recommendations&#34;: {&#34;sourcePage&#34;: &#34;&#34;, &#34;sourceType&#34;: 0, &#34;sourceRank&#34;: 0, &#34;sourceIdenticalDescriptions&#34;: 0, &#34;sourceTitleWords&#34;: 0, &#34;sourceDescriptionWords&#34;: 0, &#34;experiment&#34;: &#34;&#34;}, &#34;experiment&#34;: {&#34;ids&#34;: &#34;&#34;}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <firebase-gtm></firebase-gtm> <firebase-utm></firebase-utm> <script nonce="gYM6GevnMwgWrsGN/6Emj5oVlDPs0R"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/js/app_loader.js', '[4,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f","https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase","https://firebase-dot-devsite-v2-prod.appspot.com",1,null,["/_pwa/firebase/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/favicon.png","https://www.gstatic.com/devrel-devsite/prod/v38a693baeb774512feb42f10aac8f755d8791ed41119b5be7a531f8e16f8279f/firebase/images/lockup.svg","https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,116,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyAP-jjEJBzmIyKR4F-3XITp8yM9T1gEEI8","AIzaSyB6xiKGDR5O3Ak2okS4rLkauxGUG7XP0hg","firebase.google.com","AIzaSyAQk0fBONSGUqCNznf6Krs82Ap1-NV6J4o","AIzaSyCCxcqdrZ_7QMeLCRY20bh_SXdAYqy70KY",null,null,null,["Cloud__enable_legacy_calculator_redirect","Search__enable_page_map","Cloud__enable_llm_concierge_chat","Cloud__enable_cloud_facet_chat","Profiles__enable_complete_playlist_endpoint","MiscFeatureFlags__emergency_css","Profiles__enable_stripe_subscription_management","Profiles__enable_recognition_badges","Profiles__enable_completequiz_endpoint","Search__enable_dynamic_content_confidential_banner","DevPro__enable_developer_subscriptions","CloudShell__cloud_shell_button","DevPro__enable_cloud_innovators_plus","TpcFeatures__enable_unmirrored_page_left_nav","BookNav__enable_tenant_cache_key","MiscFeatureFlags__enable_view_transitions","Profiles__enable_profile_collections","Cloud__enable_cloud_shell","Cloud__enable_cloudx_ping","Concierge__enable_concierge","Concierge__enable_pushui","Cloud__enable_cloudx_experiment_ids","MiscFeatureFlags__enable_dark_theme","Profiles__enable_join_program_group_endpoint","Cloud__enable_free_trial_server_call","MiscFeatureFlags__enable_project_variables","Profiles__require_profile_eligibility_for_signin","Profiles__enable_completecodelab_endpoint","Profiles__enable_page_saving","Experiments__reqs_query_experiments","EngEduTelemetry__enable_engedu_telemetry","MiscFeatureFlags__developers_footer_dark_image","Cloud__enable_cloud_shell_fte_user_flow","Search__enable_ai_eligibility_checks","Significatio__enable_by_tenant","Profiles__enable_public_developer_profiles","MiscFeatureFlags__enable_variable_operator","Profiles__enable_developer_profiles_callout","CloudShell__cloud_code_overflow_menu","Profiles__enable_dashboard_curated_recommendations","Search__enable_suggestions_from_borg","MiscFeatureFlags__enable_firebase_utm","Analytics__enable_clearcut_logging","MiscFeatureFlags__developers_footer_image","Profiles__enable_release_notes_notifications","Profiles__enable_awarding_url","Search__enable_ai_search_summaries","Cloud__enable_cloud_dlp_service","MiscFeatureFlags__enable_explain_this_code","TpcFeatures__enable_mirror_tenant_redirects"],null,null,"AIzaSyBLEMok-5suZ67qRPzx0qUtbnLmyT_kCVE","https://developerscontentserving-pa.clients6.google.com","AIzaSyCM4QpTRSqP5qI4Dvjt4OAScIN8sOUlO-k","https://developerscontentsearch-pa.clients6.google.com",1,4,null,"https://developerprofiles-pa.clients6.google.com",[4,"firebase","Firebase","firebase.google.com",null,"firebase-dot-devsite-v2-prod.appspot.com",null,null,[1,1,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],[1,null,null,[1]],null,null,null,[1,null,1],[1,1,null,null,1]],null,[68,null,null,null,null,null,"/images/lockup.svg","/images/touchicon-180.png",null,null,null,1,1,1,null,null,null,null,null,null,null,2,null,null,null,"/images/lockup.svg",[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[6,1,20,22,23,29,37],null,[[],[1,1]],[[null,null,null,null,["UA-24532603-9"],["GTM-N84485"],null,null,null,null,[["UA-24532603-9",1]],[["GTM-N84485",1]],1],[[36,4],[46,8],[16,2],[17,1],[2,5]],null,1],null,4],null,"pk_live_5170syrHvgGVmSx9sBrnWtA5luvk9BwnVcvIi7HizpwauFG96WedXsuXh790rtij9AmGllqPtMLfhe2RSwD6Pn38V00uBCydV4m",1]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10