enappd loader


Connecting Cloud Firestore Database to Flutter Voting App



Introduction

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.

What you’ll build?

In this tutorial, you’ll build a mobile app featuring realtime Cloud Firestore Database using the Flutter SDK. Your app will:

  • Display a voting interface connected to a Firestore database.
  • Update the database on the cloud as you tap on a particular vote.

That’s how the final implementation gonna look like

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.

Github Repository | @ShivamGoyal1899

Package Used | cloud_firestore


Setting up Flutter on your machine

The detailed steps to install Flutter on your personal computer & getting started with Flutter is available at the following blog post

Adding Firebase to your Flutter App

This tutorial requires already setup Firebase. The detailed steps to integrate Firebase with Flutter is available at the following blog post

Your Firebase-Flutter setup is finished, and you’re ready to start building your app!

Create your Cloud Firestore database

You’ll start by setting up Cloud Firestore and initializing it with some values.

  • Open the Firebase console, then select the Firebase project that you created during setup.
  • From the left nav Develop section, select Database.


  • In the Cloud Firestore pane, click Create database.


  • In the Secure rules for Cloud Firestore dialog, select Start in test mode, then click Next. On the next screen, select Cloud Firestore location. I suggest selecting nam5 (us-central) . However, you can select according to your preference.
  • 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.




  • Our database will have one collection, that we’ll name “candidate”. In the collection is where the names and votes are stored. Click Start Collection, set the collection’s ID to candidate, then click Next.


  • You can now add documents to your collection. Each document has a Document ID, and we’ll need to have name and votes fields.
  • Enter a candidate name using all lowercase letters. In this example, we used tom.
    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.


  • For the existing Field, enter the value of name, select string for the Type, then enter the Value of Tom.
  • Click the Add Field icon to add a second field to contain the number of votes. Select number for the Type, then initialize the Value as 0.
  • Click Save.
  • Add additional baby names by clicking Add Document.
    After adding several documents to your collection, your database should look something like this:


Coding the application

Add Cloud Firestore plugin to your app

  • From the root directory of your Flutter app, open your pubspec.yaml file.
  • Add the FlutterFire plugin for the Cloud Firestore. All Flutter apps with Cloud Firestore, both iOS and Android versions, require the cloud_firestore plugin.
dependencies:
flutter:
sdk: flutter
firebase_core: ^0.2.5  # add dependency for Firebase Core
cloud_firestore: ^0.8.2  # add dependency for Cloud Firestore
  • Run flutter packages get.

Adding the User Interface

  • Using your IDE or editor, open lib/main.dart. This file currently contains the entire code for the default Flutter app.
  • Delete all of the code in main.dart, then replace it with the following:

  • Save the file, then hot-reload your app. You should see the following app:


Mock created with dummyData
  • 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 main.dart is structured.

The first half of this program is fairly straightforward:

  • You imported cloud_firestore.dart, a plugin for communicating with the Cloud Firestore.
  • You added some dummy data (soon to be replaced by a Cloud Firestore instance).
  • You set the app’s title to Voting Panel.

The interesting part of the code is in _MyHomePageState. The build method in this block defines the widget hierarchy that Flutter uses to create the display for your app.

  • The app has an AppBar (with a title of Voting Panel).
  • The app’s body contains a ListView, which renders each of the dummy data points as individual list items.

The longest method by far is _buildListItem, which tells Flutter how to build each item in the list (displayed as the rounded rectangles with candidate names and the number of votes).

Lastly, you have Record, 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.

Connect your Flutter app to Cloud Firestore

Our app is now connected to Cloud Firestore! It’s time to fetch our collection (candidate) and use it instead of our dummySnapshot object.

From Dart, you get the reference to Cloud Firestore by calling Firestore.instance. Specifically for our collection of baby names, call Firestore.instance.collection('candidate').snapshots() to return a stream of snapshots.

Let’s plug that stream of data into our Flutter UI using a StreamBuilder widget.

  • In your IDE or editor, open lib/main.dart, then find the _buildBody method.
  • Replace the entire method with the following code:
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('candidate').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();

return _buildList(context, snapshot.data.documents);
},
);
}
  • The code that you just copy-pasted has a type error. It’s trying to pass a list of DocumentSnapshot to a method that expects something else. Find _buildList and change its signature to this:
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
...
  • Instead of a list of Map, it now takes a list of DocumentSnapshot.
  • We’re almost there. The method _buildListItem still thinks it's getting a Map. Find the start of the method, then replace it with this:
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
  • Instead of a Map, you're now taking a DocumentSnapshot, and using the Record.fromSnapshot() named constructor to build the Record. Remove the dummySnapshot field from the top of lib/main.dart. It's not needed anymore.
  • Save the file, then hot-reload your app. After about a second, your app should look like this:


Reading from the Cloud Firestore database

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!).

Add interactivity

Next you will allow users to actually vote!

  • In lib/main.dart, find the line that says onTap: () => print(record). Change it to this:
onTap: () => record.reference.updateData({'votes': record.votes+1})

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.

  • Save the file, then hot-reload your app.

Voting is now functional, including the update to the user interface.

How does this work?
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 StreamBuilder implemented above, it's updated with the new data.

Here are the final contents of lib/main.dart.



Building & running the application

  • Connect your Emulator or physical Android device to test the application.
  • Click on Build & Run.
  • And Boooom 🔥, your app is ready.
    The final build would look like the below illustration.





Title
Subtitle
Kicker