Introduction to using Firestore and new Firestore features in TMS WEB Core v1.7
This article is the first in a 4 part series that will
explore the new features available in the TWebFirestoreClientDataSet component
in TMS Web Core v1.7.
A quick summary of the basic features in the previous
version of Firestore ClientDataSet component
Here’s a quick introduction for those developers who have
not had a chance to use the component so far.
TWebFirestoreClientDataSet was introduced in TMS Web Core
v1.3 to enable the developers to use Google Firestore as a cloud-hosted, NoSQL
database for their web apps. By using this component, you can use a Google
Firestore collection as a dataset and get a full CRUD functionality to update
it. As you make changes to the dataset, the component updates the Firestore
collection behind the scenes. What is more, since the component is a
ClientDataSet, you can bind the component to various DB-aware TMS WEB Core UI
controls via a TWebDataSource.
Here are the steps to use a Firestore collection as a
dataset:
- In order to connect to a Firestore collection, all you
have to do is drop a TWebFirestoreClientDataSet component on a form and set a
few Firebase properties and CollectionName in it. Then define the dataset
fields either in design view or in code and make the component Active. - Additionally, you can bind the component to various
DB-aware TMS WEB Core UI controls via a TWebDataSource. What you get is a basic
App with a CRUD functionality out-of-the-box. A Firestore collection is created
automatically as soon as you insert the first record. Any dataset updates you
make in code or via the DB-aware controls are automatically sent to Firestore
collection by the component. - Further, the basic authentication of a Google Sign-In is
also available in the component so that you can force the user to Sign-In with
Google before the data in the Firestore collection can be accessed. This
requires a simple Authentication rule to be set up in the Firestore dashboard. Then
all you need to do in the component is switch ON its property SignInIsRequired.
It takes care of presenting a Google Sign-In popup as soon as you make the
dataset active.
Complete details for the above steps are given in the TMSWeb Core Firestore documentation.
You will also find a TodoList Demo in the folder
“DemoDBBackendFirestore” that demonstrates the above features.
Please follow the instructions in the TMS Web Core Firestore documentation to
set up and run this Demo.
Here is a screenshot of the demo:
What you will see in action is a web app that displays the
Task records from a Firestore collection called “Tasks” and provides
the features to edit the data by means of various DB-aware controls bound to
the data source. It also prompts for a Google Sign-In if the user is not signed
in.
Although the basic demo does a good job of showing the CRUD
features, it has some problems in the way its start up logic is coded and there
is a reason for it as explained below.
- The demo expects the end user to enter the API Key and
other Firebase parameters - The values for these parameters are used to set Firebase
properties in the Firestore ClientDataSet after the Open button is clicked - The values are remembered in the local storage to be used
in the next session
The reason the basic demo is coded this way is for the
convenience of you as a developer when setting up Firebase for the first time.
The API Key or some other parameter may not work as you learn the process of
set up. Hence, it gives entry boxes for you to experiment till you get them right
and remembers the parameters for the next session.
But this is not the way a real Web App will work!
Please do not follow the above model for your own web app
that uses Firestore ClientDataSet.
Here is an attempt to explain why the above approach in the
basic demo is wrong and should not be taken as sample code for your own web
app:
- In reality, a web app should never prompt for the Firebase
parameters from the user. Setting them belongs in the code or in the object
inspector. For the same reason, the Firebase parameters are not remembered in
the local storage as they are not prompted for. - The App should subscribe to Firebase sign-in events as
soon as it starts in order to know whether a user is already signed-in. This is
to give a good start up experience to the user. And the Subscribe method needs
the Firebase parameters to be set so they can not be postponed to be set later
on a button click as the basic demo does.
If you see the new Multi-Tenant Demo described later, it
follows the correct approach of setting up these parameters in the code and
getting the status of the signed-in user to open the dataset automatically.
Also it remembers the Email address of the user in local storage which is
convenient for the user.
New Sign-In features in the Firestore ClientDataSet
component
In this part 1 of the series, we take a look at the new
Sign-In related features. There are plenty of them.
Sign-In by Email/Password is now supported
The earlier version of the Firestore ClientDataSet Component
only supported Google Sign-In method. Many users do not want to sign up for web
apps with their Google Sign-In. They prefer to sign up with a custom email
address and password for privacy reasons. Hence, the Email/Password method of
Firebase Sign-In is popular with web apps as it gives them a complete control
over authentication right up to the reset password feature often needed by
users.
Your TMS Web Core App can support the Email/Password Sign-In
method of Firebase by using the following features of the
TWebFirestoreClientDataSet component.
Enable Email/Password Sign-In method in Firebase
Console first
-
First of all, you need to enable the Email/Password Sign-In
method in the authentication section of the Firebase console.
Let the user Sign-Up
-
Use your own interface in the web app to collect the
sign-up email address and password from the user - Call the method SignInAsync with the given email and
password. Pass a True value for the IsSignUp flag.
The suffix “Async” of the method name
“SignInAsync” means that you can get the success or failure result of
the call by passing an anonynous response procedure to the method. Here is the
sample code.
fireStoreClientDataSet.SignInAsync( aUserEmail, aPassword, True, // IsSignup flag procedure(success: Boolean; errorName, errorMsg: String) begin // do something on success or failure end );
Let the user Sign-In
-
Use your own interface to collect the sign-in email
address and password from the user - Call the same method SignInAsync with the given email,
password and a False value for the IsSignUp flag.
Let the user Reset Password
-
To provide this functionality in the App, call the method
SendPasswordResetEmail. This tells Firebase to send an Email to the user with a
special link to reset the password. You can customize the contents of this
email in the Firebase console.
fireStoreClientDataSet.SendPasswordResetEmail( aUserEmail, procedure(success: Boolean; errorName, errorMsg: String) begin if not success then begin showmessage(errorMsg); exit; end; ... Success actions like ... asking the user to check email ... and follow the instructions end );
It’s good to know that the Firebase Console also helps
manage the users
- In addition to the above features given by the component,
you get the features to manage the users in the Firebase console too. There,
you can see the list of Users in the Authentication section from where you can
disable a user, delete a user or even initiate a reset password for the user.
Getting the Signed-In status and acting on it is now
easier
The features to get
the Signed-In status are needed in order to present a better interface to the
user who may want to remain signed in.
Better example of using SubscribeToSignInEvents
The previous version of TWebFirestoreClientDataSet component
already had a method SubscribeToSignInEvents that allows you to get a Sign-In
event whenever a user signed in or signed out of your web app. This method
enables the web app to change the user interface according to the Signed-In
status. But as already explained earlier, the basic TodoList demo does not use
this feature properly because it prompts for the Firebase parameters and calls
SubscribeToSignInEvents only after a successful Sign In.
In reality, a web app will not prompt for firebase
parameters and would rather set them during the initialization of the App. Also
the App would then immediately call the SubscribeToSignInEvents method to let a
common OnSignInChange event change the interface accordingly.
For example, an App may hide the Sign-In panel and display
the Signed-In user’s identity. This way the App can change its user interface
to show a Signed-In state. The new Firestore Multi-Tenant Demo (folder
DemoServicesFirestore) has the proper sample code that demonstrates this
approach.
The Sign-In panel in the new
Multi-Tenant Demo
In this demo, the Sign-In panel appears only if the user is
not signed in.
![alt SignIn Panel in the Multi-Tenant
Demo](./SigninPanel.png “SignIn Panel in the Multi-Tenant Demo”)
How the interface changes after Sign In is described in the
next section along with a screenshot.
To see the exact implementation, please see the code and
comments in the Firestore Multi-Tenant Demo (folder DemoServicesFirestore).
Please note that this is just an example. It’s up to you how you prompt for
Sign-In credentials. You can even design your own Modal popup to ask for that.
GetSignedInUserAsync Method to take one-time actions
If you have used the Sign-In event feature in the previous
version, you may have realized that a Sign-In event may occur multiple times
for a web app whenever a user signs in and out of web app. Hence, it does not
give you a clean way to do something only once if the user is already signed
in.
For example, assume that a user Email is remembered from the
last session in local storage. On startup, the App finds that the same user is
already logged in to Firebase. In this case, it can open the dataset
automatically to give the user a nice start up experience.
For this purpose, you can use the method
GetSignedInUserAsync that gives you the user information of the signed-in user
through the anonymous procedure that you pass to it.
Here is the sample code from the new Firestore Multi-Tenant
Demo (folder DemoServicesFirestore). It automatically opens the dataset if
the same user who intends to sign-in is already signed in.
fireStoreClientDataSet.GetSignedInUserAsync( procedure(isSignIn: Boolean; UserName: String; UserEmail: String) begin if isSignIn then begin if (edEmail.Text <> '') and SameText(edEmail.Text, UserEmail) then openDatabase; end; end );
The Multi-Tenant Demo after the user
Signs In
Once the Sign-In occurs or if the user is already found
Signed In by the App at start up, the following screen appears where the Sign-In
panel is hidden and another control panel appears. Notice how the Signed-In
user’s email is shown and a Sign-Out button is provided. User may or may not
Sign Out when closing the browser. Next time when the user starts the App, it
is smart enough to detect a signed in status and open the dataset
automatically.
![alt User has Signed In](./SignedInStatus.png “User
has Signed In”)
To see how this approach is implemented, please see the code
and comments in the Firestore Multi-Tenant Demo folder DemoServicesFirestore).
Letting the user Sign-Out
To Sign Out of Firebase, you need to call the SignOut method
of the component. But you need to close the dataset before you do that
otherwise it will generate a usage error. SignOut does not do a close automatically.
It depends on the App to close prior to sign-out because only the App knows its
proper state whether it is safe to close.
Summary of what we learned in this article
- First, we had a brief look at the basic features of
Firestore ClientDataSet component for those of you who haven’t had a chance to
use it. - Next we described the new Sign-In related features of the
component that give you the popular Email/Password authentication of Firebase
out-of-the-box by the use of a simple flag. - We also discussed the proper approach to detect a
signed-in user in order to provide a nice user experience. - Then we looked at the new Multi-Tenant Demo that uses
these new sign-in features in the recommended way.
In the next part 2 of this series, we are going to take a
look at the Multi-Tenant capability of the Firestore ClientDataSet component
that allows to keep the data of each signed-in user separate and safe.