Connecting Cloud Firestore Database to Flutter
Tags: flutter, firebase, firestore, cloud
Published: 2020-03-25 21:53:56

<section name="2c74" class="section section--body section--first"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><p name="c874" class="graf graf--p graf-after--figure">Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud Platform. Like Firebase Realtime Database, it keeps your data in-sync across client apps through realtime listeners and offers offline support for mobile and web so you can build responsive apps that work regardless of network latency or Internet connectivity. Cloud Firestore also offers seamless integration with other Firebase and Google Cloud Platform products, including Cloud Functions.</p><h4 name="c87f" class="graf graf--h4 graf-after--p">What you’ll&nbsp;build?</h4><p name="1aad" class="graf graf--p graf-after--h4">In this tutorial, you’ll build a mobile app featuring realtime Cloud Firestore Database using the Flutter SDK. Your app will:</p><ul class="postList"><li name="2b05" class="graf graf--li graf-after--p">Display a voting interface connected to a Firestore database.</li><li name="a593" class="graf graf--li graf-after--li">Update the database on the cloud as you tap on a particular vote.</li></ul><figure tabindex="0" contenteditable="false" name="f64e" class="graf graf--figure graf-after--li"><div class="aspectRatioPlaceholder"><img class="graf-image" data-image-id="0*PqwflenUVNH0wIBC.png" src="https://cdn-images-1.medium.com/max/720/0*PqwflenUVNH0wIBC.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">That’s how the final implementation gonna look&nbsp;like</figcaption></figure><p name="602e" class="graf graf--p graf-after--figure">This tutorial focuses on adding Cloud Firestore to a Flutter app. Non-relevant concepts and code blocks are glossed over and are provided for you to simply copy and paste.</p><h4 name="3aaa" class="graf graf--h4 graf-after--p">Package Used | <a href="https://pub.dev/packages/cloud_firestore"  class="markup--anchor markup--h4-anchor"    target="_blank">cloud_firestore</a></h4><p name="f633" class="graf graf--p graf--empty graf-after--h4 graf--trailing" ><br></p></div></div></section><section name="f2f6" class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 name="2e7e" class="graf graf--h3 graf--leading">Setting up Flutter on your&nbsp;machine</h3><p name="f77d" class="graf graf--p graf-after--h3">The detailed steps to install Flutter on your personal computer &amp; getting started with Flutter is available at the following blog post <a href="https://medium.com/enappd/install-flutter-on-windows-and-mac-1fd1dde453ba"  class="markup--anchor markup--p-anchor"    target="_blank">here</a>.</p><h3 name="7f78" class="graf graf--h3 graf-after--p">Adding Firebase to your Flutter&nbsp;App</h3><p name="a3a8" class="graf graf--p graf-after--h3">This tutorial requires already setup Firebase. The detailed steps to integrate Firebase with Flutter is available at the following blog post <a href="https://medium.com/enappd/adding-firebase-to-your-flutter-app-281b8f391b47"  class="markup--anchor markup--p-anchor"    target="_blank">here</a>.</p><p name="d78f" class="graf graf--p graf-after--p">Your Firebase-Flutter setup is finished, and you’re ready to start building your app!</p><h3 name="269c" class="graf graf--h3 graf-after--p"><strong class="markup--strong markup--h3-strong">Create your Cloud Firestore database</strong></h3><p name="d204" class="graf graf--p graf-after--h3">You’ll start by setting up Cloud Firestore and initializing it with some values.</p><ul class="postList"><li name="6943" class="graf graf--li graf-after--p">Open the <a href="https://console.firebase.google.com/"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Firebase console</a>, then select the Firebase project that you created during setup.</li><li name="ced7" class="graf graf--li graf-after--li">From the left nav <strong class="markup--strong markup--li-strong">Develop</strong> section, select <strong class="markup--strong markup--li-strong">Database</strong>.</li></ul><figure tabindex="0" contenteditable="false" name="e35c" class="graf graf--figure graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 308px; max-height: 340px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 110.4%;"></div><img class="graf-image" data-image-id="1*0um9HaWpBX_X_SiuXhA8jg.png" data-width="308" data-height="340" src="https://cdn-images-1.medium.com/max/720/1*0um9HaWpBX_X_SiuXhA8jg.png"><div class="crosshair u-ignoreBlock"></div></div></figure><ul class="postList"><li name="25b5" class="graf graf--li graf-after--figure">In the <strong class="markup--strong markup--li-strong">Cloud Firestore</strong> pane, click <strong class="markup--strong markup--li-strong">Create database</strong>.</li></ul><figure tabindex="0" contenteditable="false" name="701d" class="graf graf--figure graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 522px; max-height: 294px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 56.3%;"></div><img class="graf-image" data-image-id="1*s_0SYZq2gL_BUbJLem_mSA.png" data-width="522" data-height="294" src="https://cdn-images-1.medium.com/max/720/1*s_0SYZq2gL_BUbJLem_mSA.png"><div class="crosshair u-ignoreBlock"></div></div></figure><ul class="postList"><li name="8174" class="graf graf--li graf-after--figure is-selected">In the <strong class="markup--strong markup--li-strong">Secure rules for Cloud Firestore dialog</strong>, select <strong class="markup--strong markup--li-strong">Start in test mode</strong>, then click <strong class="markup--strong markup--li-strong">Next</strong>. On the next screen, select <strong class="markup--strong markup--li-strong">Cloud Firestore location</strong>. I suggest selecting <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">nam5 (us-central)</strong></code><strong class="markup--strong markup--li-strong">&nbsp;</strong>. However, you can select according to your preference.</li><li name="a1a2" class="graf graf--li graf-after--li">Test mode allows any user to read and write to your database, which is convenient during development. However, this can be a security risk. Before releasing an app to production, you should add security rules.</li></ul><figure tabindex="0" contenteditable="false" name="ecb1" class="graf graf--figure graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 540px; max-height: 428px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 79.3%;"></div><img class="graf-image" data-image-id="1*Bm9EyN60KIJzOHakHLQ3iQ.png" data-width="540" data-height="428" src="https://cdn-images-1.medium.com/max/720/1*Bm9EyN60KIJzOHakHLQ3iQ.png"><div class="crosshair u-ignoreBlock"></div></div></figure><figure tabindex="0" contenteditable="false" name="67fc" class="graf graf--figure graf-after--figure is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 540px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 77.10000000000001%;"></div><img class="graf-image" data-image-id="1*CBO-PoNGpRk9SaoZOvToOg.png" data-width="720" data-height="555" src="https://cdn-images-1.medium.com/max/720/1*CBO-PoNGpRk9SaoZOvToOg.png"><div class="crosshair u-ignoreBlock"></div></div></figure><ul class="postList"><li name="0e22" class="graf graf--li graf-after--figure">Our database will have one collection, that we’ll name “candidate”. In the collection is where the names and votes are stored. Click <strong class="markup--strong markup--li-strong">Start Collection</strong>, set the collection’s ID to <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">candidate</strong></code>, then click <strong class="markup--strong markup--li-strong">Next</strong>.</li></ul><figure tabindex="0" contenteditable="false" name="bf77" class="graf graf--figure graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 401px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 57.3%;"></div><img class="graf-image" data-image-id="1*duF9HT0AhhCogMhu4jWrzQ.png" data-width="904" data-height="518" src="https://cdn-images-1.medium.com/max/720/1*duF9HT0AhhCogMhu4jWrzQ.png"><div class="crosshair u-ignoreBlock"></div></div></figure><ul class="postList"><li name="7bab" class="graf graf--li graf-after--figure">You can now add documents to your collection. Each document has a <strong class="markup--strong markup--li-strong">Document ID</strong>, and we’ll need to have <strong class="markup--strong markup--li-strong">name </strong>and <strong class="markup--strong markup--li-strong">votes </strong>fields.</li><li name="62e2" class="graf graf--li graf-after--li">Enter a candidate name using all lowercase letters. In this example, we used <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">tom</strong></code>.<br>Using an actual candidate name for each Document ID ensures that the documents are displayed alphabetically by candidate name. By default, Document IDs are auto-generated timestamps, and documents are displayed in the order that they were created.</li></ul><figure tabindex="0" contenteditable="false" name="6752" class="graf graf--figure graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 619px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 88.5%;"></div><img class="graf-image" data-image-id="1*63_Zqzp3VacQrWo7Bdwp9w.png" data-width="893" data-height="790" src="https://cdn-images-1.medium.com/max/720/1*63_Zqzp3VacQrWo7Bdwp9w.png"><div class="crosshair u-ignoreBlock"></div></div></figure><ul class="postList"><li name="398c" class="graf graf--li graf-after--figure">For the existing <strong class="markup--strong markup--li-strong">Field</strong>, enter the value of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">name</strong></code>, select <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">string</strong></code><strong class="markup--strong markup--li-strong"> </strong>for the <strong class="markup--strong markup--li-strong">Type</strong>, then enter the <strong class="markup--strong markup--li-strong">Value</strong> of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">Tom</strong></code>.</li><li name="d732" class="graf graf--li graf-after--li">Click the <strong class="markup--strong markup--li-strong">Add Field</strong> icon to add a second field to contain the number of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">votes</strong></code>. Select <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">number</strong></code><strong class="markup--strong markup--li-strong"> </strong>for the <strong class="markup--strong markup--li-strong">Type</strong>, then initialize the <strong class="markup--strong markup--li-strong">Value</strong> as <code class="markup--code markup--li-code">0</code>.</li><li name="d90b" class="graf graf--li graf-after--li">Click <strong class="markup--strong markup--li-strong">Save</strong>.</li><li name="a92b" class="graf graf--li graf-after--li">Add additional baby names by clicking <strong class="markup--strong markup--li-strong">Add Document</strong>.<br>After adding several documents to your collection, your database should look something like this:</li></ul></div><div class="section-inner sectionLayout--outsetColumn"><figure tabindex="0" contenteditable="false" name="6267" class="graf graf--figure graf--layoutOutsetCenter graf-after--li"><div class="aspectRatioPlaceholder is-locked" style="max-width: 1192px; max-height: 331px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 27.800000000000004%;"></div><img class="graf-image" data-image-id="1*FxZ97mib5tTeuU-ik161qw.png" data-width="1446" data-height="402" src="https://cdn-images-1.medium.com/max/1080/1*FxZ97mib5tTeuU-ik161qw.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Firestore Console</figcaption></figure></div><div class="section-inner sectionLayout--insetColumn"><h3 name="edf9" class="graf graf--h3 graf-after--figure">Coding the application</h3><h4 name="e54f" class="graf graf--h4 graf-after--h3">Add Cloud Firestore plugin to your&nbsp;app</h4><ul class="postList"><li name="eeb8" class="graf graf--li graf-after--h4">From the root directory of your Flutter app, open your <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">pubspec.yaml</strong></code> file.</li><li name="895b" class="graf graf--li graf-after--li">Add the FlutterFire plugin for the Cloud Firestore. All Flutter apps with Cloud Firestore, both iOS and Android versions, require the <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">cloud_firestore</strong></code> plugin.</li></ul><figure tabindex="0" contenteditable="false" name="8c34" class="graf graf--figure graf--iframe graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/ShivamGoyal1899/3c8ab0e9ccbea4d0eaea662dd688767c.js %}</div></div></figure><ul class="postList"><li name="0975" class="graf graf--li graf-after--figure">Run <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">flutter packages get</strong></code>.</li></ul><h4 name="d30c" class="graf graf--h4 graf-after--li">Adding the User Interface</h4><ul class="postList"><li name="f25a" class="graf graf--li graf-after--h4">Using your IDE or editor, open <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">lib/main.dart</strong></code>. This file currently contains the entire code for the default Flutter app.</li><li name="aab2" class="graf graf--li graf-after--li">Delete all of the code in <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">main.dart</strong></code>, then replace it with the following:</li></ul><figure tabindex="0" contenteditable="false" name="8f35" class="graf graf--figure graf--iframe graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/ShivamGoyal1899/3820de2e1c608ff2fabb2e0e7038371e.js %}</div></div></figure><ul class="postList"><li name="1840" class="graf graf--li graf-after--figure">Save the file, then <strong class="markup--strong markup--li-strong">hot-reload</strong> your app. You should see the following app:</li></ul><figure tabindex="0" contenteditable="false" name="b028" class="graf graf--figure graf-after--li"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 1244px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 177.8%;"></div><img class="graf-image" data-image-id="1*qulyUYpUb9_6v12RZPsmqQ.png" data-width="1080" data-height="1920" src="https://cdn-images-1.medium.com/max/720/1*qulyUYpUb9_6v12RZPsmqQ.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Mock created with dummyData</figcaption></figure><ul class="postList"><li name="adf2" class="graf graf--li graf-after--figure">The app is currently just a mock. Clicking on names only prints to the console. The next step is to connect this app to Cloud Firestore. Before doing that, you can read about how the code in <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">main.dart</strong></code> is structured.</li></ul><p name="43a3" class="graf graf--p graf-after--li">The first half of this program is fairly straightforward:</p><ul class="postList"><li name="da9a" class="graf graf--li graf-after--p">You imported <code class="markup--code markup--li-code u-paddingRight0 u-marginRight0"><strong class="markup--strong markup--li-strong">cloud_firestore.dart</strong>,</code> a plugin for communicating with the Cloud Firestore.</li><li name="acd5" class="graf graf--li graf-after--li">You added some dummy data (soon to be replaced by a Cloud Firestore instance).</li><li name="f1a5" class="graf graf--li graf-after--li">You set the app’s title to <strong class="markup--strong markup--li-strong">Voting Panel</strong>.</li></ul><p name="240c" class="graf graf--p graf-after--li">The interesting part of the code is in <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">_MyHomePageState</strong></code>. The <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">build</strong></code><strong class="markup--strong markup--p-strong"> </strong>method in this block defines the widget hierarchy that Flutter uses to create the display for your app.</p><ul class="postList"><li name="3507" class="graf graf--li graf-after--p">The app has an <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">AppBar</strong></code> (with a title of <strong class="markup--strong markup--li-strong">Voting Panel</strong>).</li><li name="6e8a" class="graf graf--li graf-after--li">The app’s body contains a <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">ListView</strong></code>, which renders each of the dummy data points as individual list items.</li></ul><p name="55fd" class="graf graf--p graf-after--li">The longest method by far is <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">_buildListItem</strong></code>, which tells Flutter how to build each item in the list (displayed as the rounded rectangles with candidate names and the number of votes).</p><p name="2db1" class="graf graf--p graf-after--p">Lastly, you have <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">Record</strong></code>, the convenience class that holds a single record for a name. You don't strictly need this class for a simple app like this to function, but it makes the code a bit cleaner.</p><h4 name="176a" class="graf graf--h4 graf-after--p">Connect your Flutter app to Cloud Firestore</h4><p name="5293" class="graf graf--p graf-after--h4">Our app is now connected to Cloud Firestore! It’s time to fetch our collection (<code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">candidate</strong></code>) and use it instead of our <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">dummySnapshot</strong></code><strong class="markup--strong markup--p-strong"> </strong>object.</p><p name="fcdc" class="graf graf--p graf-after--p">From Dart, you get the reference to Cloud Firestore by calling <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">Firestore.instance</strong></code>. Specifically for our collection of baby names, call <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">Firestore.instance.collection('candidate').snapshots()</strong></code> to return a <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">stream</strong></code><strong class="markup--strong markup--p-strong"> </strong>of snapshots.</p><p name="f92f" class="graf graf--p graf-after--p">Let’s plug that stream of data into our Flutter UI using a <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">StreamBuilder</strong></code><strong class="markup--strong markup--p-strong"> </strong>widget.</p><ul class="postList"><li name="877e" class="graf graf--li graf-after--p">In your IDE or editor, open <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">lib/main.dart</strong></code>, then find the <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">_buildBody</strong></code><strong class="markup--strong markup--li-strong"> </strong>method.</li><li name="9e33" class="graf graf--li graf-after--li">Replace the entire method with the following code:</li></ul><figure tabindex="0" contenteditable="false" name="cce7" class="graf graf--figure graf--iframe graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/ShivamGoyal1899/13bbcb8d36b86ea7cb59eb9a19ffe9f1.js %}</div></div></figure><ul class="postList"><li name="de7a" class="graf graf--li graf-after--figure">The code that you just copy-pasted has a type error. It’s trying to pass a list of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">DocumentSnapshot</strong></code><strong class="markup--strong markup--li-strong"> </strong>to a method that expects something else. Find <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">_buildList</strong></code><strong class="markup--strong markup--li-strong"> </strong>and change its signature to this:</li></ul><pre name="3c75" class="graf graf--pre graf-after--li"><code class="markup--code markup--pre-code u-paddingRight0 u-marginRight0"><strong class="markup--strong markup--pre-strong">Widget</strong> _buildList(BuildContext context, List&lt;DocumentSnapshot&gt; snapshot) {<br>  ...</code></pre><ul class="postList"><li name="acf3" class="graf graf--li graf-after--pre">Instead of a list of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">Map</strong></code>, it now takes a list of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">DocumentSnapshot</strong></code>.</li><li name="b1ef" class="graf graf--li graf-after--li">We’re almost there. The method <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">_buildListItem</strong></code><strong class="markup--strong markup--li-strong"> </strong>still thinks it's getting a <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">Map</strong></code>. Find the start of the method, then replace it with this:</li></ul><pre name="336d" class="graf graf--pre graf-after--li"><code class="markup--code markup--pre-code u-paddingRight0 u-marginRight0"><strong class="markup--strong markup--pre-strong">Widget</strong> _buildListItem(BuildContext context, DocumentSnapshot data) {<br> final record = Record.fromSnapshot(data);</code></pre><ul class="postList"><li name="95f7" class="graf graf--li graf-after--pre">Instead of a <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">Map</strong></code>, you're now taking a <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">DocumentSnapshot</strong></code>, and using the <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">Record.fromSnapshot()</strong></code> named constructor to build the <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">Record</strong></code>. Remove the <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">dummySnapshot</strong></code><strong class="markup--strong markup--li-strong"> </strong>field from the top of <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">lib/main.dart</strong></code>. It's not needed anymore.</li><li name="8414" class="graf graf--li graf-after--li">Save the file, then hot-reload your app. After about a second, your app should look like this:</li></ul><figure tabindex="0" contenteditable="false" name="aa9b" class="graf graf--figure graf-after--li"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 1244px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 177.8%;"></div><img class="graf-image" data-image-id="1*brrbur5ZGdCGLrmG7-hAFA.png" data-width="1080" data-height="1920" src="https://cdn-images-1.medium.com/max/720/1*brrbur5ZGdCGLrmG7-hAFA.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Reading from the Cloud Firestore database</figcaption></figure><p name="85e5" class="graf graf--p graf-after--figure">You’ve just read from the database that you created! If you want, you can go to the Firebase console and change the database. Your app will reflect the changes almost immediately (after all Cloud Firestore is a real-time database!).</p><h4 name="4e25" class="graf graf--h4 graf-after--p">Add interactivity</h4><p name="95a2" class="graf graf--p graf-after--h4">Next, you will allow users to actually vote!</p><ul class="postList"><li name="3684" class="graf graf--li graf-after--p">In <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">lib/main.dart</strong></code>, find the line that says <code class="markup--code markup--li-code"><strong class="markup--strong markup--li-strong">onTap: () =&gt; print(record)</strong></code>. Change it to this:</li></ul><pre name="7e95" class="graf graf--pre graf-after--li"><code class="markup--code markup--pre-code u-paddingRight0 u-marginRight0"><strong class="markup--strong markup--pre-strong">onTap</strong>: () =&gt; record.reference.<strong class="markup--strong markup--pre-strong">updateData</strong>({'votes': record.votes+1})</code></pre><p name="d70e" class="graf graf--p graf-after--pre">Instead of just printing the record to the console, this new line updates the baby name’s database reference by incrementing the vote count by one.</p><ul class="postList"><li name="ca9b" class="graf graf--li graf-after--p">Save the file, then <strong class="markup--strong markup--li-strong">hot-reload</strong> your app.</li></ul><p name="a06c" class="graf graf--p graf-after--li">Voting is now functional, including the update to the user interface.</p><blockquote name="9fbd" class="graf graf--blockquote graf-after--p"><strong class="markup--strong markup--blockquote-strong">How does this work?</strong><br>When the user taps the tile containing a name, you are telling Cloud Firestore to update the data of that reference. In turn, this causes Cloud Firestore to notify all listeners with the updated snapshot. As your app is listening through the <code class="markup--code markup--blockquote-code">StreamBuilder</code> implemented above, it's updated with the new data.</blockquote><p name="8b0c" class="graf graf--p graf-after--blockquote"><strong class="markup--strong markup--p-strong">Here are the final contents of </strong><code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">lib/main.dart</strong></code><strong class="markup--strong markup--p-strong">.</strong></p><figure tabindex="0" contenteditable="false" name="4411" class="graf graf--figure graf--iframe graf-after--p is-defaultValue graf--trailing"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/ShivamGoyal1899/c88c4e16959f412513b081b58c286268.js %}</div></div></figure></div></div></section><section name="8284" class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 name="25f3" class="graf graf--h3 graf--leading">Building &amp; running the application</h3><ul class="postList"><li name="97e7" class="graf graf--li graf-after--h3">Connect your Emulator or physical Android device to test the application.</li><li name="a8a5" class="graf graf--li graf-after--li">Click on Build &amp; Run.</li><li name="e004" class="graf graf--li graf-after--li">And Boooom 🔥, your app is ready.<br>The final build would look like the below illustration.</li></ul><figure tabindex="0" contenteditable="false" name="b813" class="graf graf--figure graf-after--li graf--trailing"><div class="aspectRatioPlaceholder is-locked" style="max-width: 600px; max-height: 1066px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 177.7%;"></div><img class="graf-image" data-image-id="1*6uLYCQE4eHbxoh29dZClZQ.gif" data-width="600" data-height="1066" src="https://cdn-images-1.medium.com/max/720/1*6uLYCQE4eHbxoh29dZClZQ.gif"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">That’s how the Final Implementation will look&nbsp;like</figcaption></figure></div></div></section><section name="edd8" class="section section--body section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 name="25cc" class="graf graf--h3 graf--leading">🎯 That’s all for&nbsp;today.</h3><blockquote name="d53f" class="graf graf--pullquote graf-after--h3">If you got any queries hit me up in the comments or ping me over on <a href="mailto:hi@itsshivam.com"  class="markup--anchor markup--pullquote-anchor"    target="_blank">hi@itsshivam.com</a> 📧</blockquote><blockquote name="2643" class="graf graf--pullquote graf-after--pullquote">If you learned even a thing or two, clap your hands👏 as many times as you can to show your support! It really motivates me to contribute towards the community.</blockquote><blockquote name="5822" class="graf graf--pullquote graf-after--pullquote">Feeling too generous? <a href="https://www.paypal.me/shivamgoyal1899/"  class="markup--anchor markup--pullquote-anchor" rel="noopener"    target="_blank">Buy me a Drink</a>&nbsp;🍺</blockquote><blockquote name="3c6f" class="graf graf--pullquote graf-after--pullquote">Wanna collaborate? <a href="mailto:hi@itsshivam.com"  class="markup--anchor markup--pullquote-anchor"    target="_blank">Let’s talk some tech</a>&nbsp;😊</blockquote><blockquote name="e577" class="graf graf--pullquote graf-after--pullquote">Stalk me over on <a href="https://itsshivam.com/"  class="markup--anchor markup--pullquote-anchor" rel="noopener"    target="_blank">itsshivam.com</a>, <a href="https://github.com/ShivamGoyal1899"  class="markup--anchor markup--pullquote-anchor" rel="noopener nofollow noopener noopener noopener noopener noopener"    target="_blank">GitHub</a>, or <a href="https://linkedin.com/in/shivamgoyal1899/"  class="markup--anchor markup--pullquote-anchor" rel="noopener nofollow noopener noopener noopener noopener noopener"    target="_blank">LinkedIn</a>. 👀</blockquote><figure tabindex="0" contenteditable="false" name="9680" class="graf graf--figure graf-after--pullquote is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 17px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 2.5%;"></div><img class="graf-image" data-image-id="1*r5VeD2fV04iDy8xfmaauHA.png" data-width="727" data-height="18" src="https://cdn-images-1.medium.com/max/720/1*r5VeD2fV04iDy8xfmaauHA.png"><div class="crosshair u-ignoreBlock"></div></div></figure><p name="fac3" class="graf graf--p graf-after--figure">This article was originally published at <a href="https://enappd.com"  class="markup--anchor markup--p-anchor"    target="_blank">Enappd</a>.</p><p name="c88c" class="graf graf--p graf--empty graf-after--p graf--trailing" ><br></p></div></div></section></div></article></main>