Connect Firebase to an Elm app and read/write data to db

In this Answer, we’ll establish a connection between Firebase and our Elm application to facilitate data retrieval and modification from the database. Firebase is a popular Backend-as-a-Service (BaaS) platform provided by Google that offers multiple application development and cloud computing services. Conversely, Elm is a functional language that compiles to JS. In Elm, we facilitate ports that allow communication with the JS code, enabling us to perform database read and write operations.

Connecting our Elm application with the Firebase app involves several steps.

Step 1: Creating a real-time database in Firebase

We can create the real-time database by following the instructions provided in this Firebase as simple database to React app. Once the real-time database is created, create a key-value pair, which we will receive and modify in our Elm application.

Realtime database storing key-value pair
Realtime database storing key-value pair

Once the Firebase project is set up, we’ll copy the configuration details essential for our connection to our database. The configuration details will be presented in the following format:

const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
databaseURL: "YOUR_DATABASE_URL",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID",
measurementId: "YOUR_MEASUREMENT_ID"
};
Configure Firebase settings

You can easily customize these values to match the configuration of your specific project.

Step 2: Firebase Read and write

To communicate with firebase.js file and Elm application, we’ll use ports. We’ll define the ports for data exchange within our Main.elm file.

port firebaseWrite : String -> Cmd msg
port firebaseRead : (String -> msg) -> Sub msg

These ports will allow our Elm application to send and receive data from JS.

  • Line 1: firebaseWrite port accepts a string as an input and returns a Cmd msg (command message).

  • Line 2: firebaseRead port accepts a string as an input and returns a Sub msg (subscription to message).

To ensure data transmission between the two components, we'll incorporate these subscriptions into our firebase.js file.

app.ports.firebaseWrite.subscribe(function(data) {
firebase.database().ref("score").set(data);
});
firebase.database().ref("score").on("value", function(snapshot) {
app.ports.firebaseRead.send(snapshot.val());
});
  • Lines 1–3: firebaseWrite will listen for incoming data on this port. Whenever data is received on the port, firebase.database().ref("score").set(data); function will be invoked. This function will write the incoming data to the score key in our database.

  • Lines 5–7: firebaseRead port listens for the value event, and whenever the event occurs, the firebaseRead.send(snapshot.val()); will be triggered and snapshot.val() will retrieve the current value on the real-time database and send it to the firebaseRead port.

Step 3: Creating an Elm application

To build an Elm application, we’ll define the Model, View, Update and Subscriptions in our Elm file.

Define the Model function

This Model defines the current state of our application. In our application, we will use an integer variable to represent the score, which we intend to read from and write to the database.

type alias Model =
{ count : Maybe Int
}
Model function in elm app

The count holds our our integer value which we will initialize to 1.

Define the View function

This view is responsible for defining the content to display in our html file, and that data is rendered from the view to our html file.

-- View
view : Model -> Html Msg
view model =
case model.count of
Just n ->
Html.text <|
"The score is " ++ String.fromInt n ++ "."
Nothing ->
Html.text "Loading score ..."

The above view essentially generates the visual representation for our application from our Model state.

  • Line 3: It takes the Model as an input and returns Html Msg. This message will be rendered to our Elm application.

  • Lines 5–8: The view function renders data based on two conditions: if our count value has some integer stored in it, then display the score.

  • Lines 10–11: Otherwise, if no integer value is present, it will execute the Nothing case.

Define the Subscription function

To establish a subscription to the onClick browser event in our elm application, we'll create a subscription function that listens for this event and triggers updates to the Model.

-- Subscriptions
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ Browser.Events.onClick (Json.Decode.succeed Click)
, firebaseRead ReceiveValue
]
  • Line 3: The function accepts Model as an input and returns a Sub Msg (subscription to Messages).

  • Lines 6–8: Whenever an on-click event occurs, firebaseRead function will be invoked.

Define the Update function

The update function plays an important role in modifying the Model and generating command messages based on user interactions. The update function takes Model as an input and returns a tuple containing the modified Model and a command message.

-- Update
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Click ->
case model.count of
Just n ->
( model
, firebaseWrite (String.fromInt (n + 1))
)
Nothing ->
( model
, Cmd.none
)
  • Lines 3–4: The update function is updating the model based on the user’s click.

  • Lines 6–11: Whenever a user clicks on the web page, it checks the count value. If there is some value stored in count then increment it, and the firebaseWrite function is called, which overwrites this value on our real-time database.

  • Lines 13–16: Otherwise, just return the same model and do not run any command.

ReceiveValue value ->
case String.toInt value of
Just n ->
( { model | count = Just n }
, Cmd.none
)
Nothing ->
( model
, Cmd.none
)
  • Lines 1–2: When a value of the ReceiveValue type is received, we perform a conversion operation from String to Int.

  • Lines 3–6: if conversion is successful, we proceed to update the count within our Model.

  • Lines 7–9: Otherwise, if the conversion operation encounters an error, no action is taken.

Code example

Now, let’s look at the example where we are integrating Firebase and our Elm application. Make sure to replace the values in firebaseConfig according to your Firebase project configurations.

app.ports.firebaseWrite.subscribe(function(data) {
  firebase.database().ref("score").set(data);
});

firebase.database().ref("score").on("value", function(snapshot) {
  app.ports.firebaseRead.send(snapshot.val());
});
Integrating elm with firebase

After executing the code, we get the output, as shown in the illustration below:

After one click in the browser.
After one click in the browser.
After two more clicks the score is updated.
After two more clicks the score is updated.

By simply clicking anywhere on the screen the score variable is updated on Firebase, and the change is shown on our screen.

Conclusion

In summary, we connected with the Firebase real-time database using its configuration details. We retrieved a value by providing a specific location score in the database, storing it in the Elm count variable, and displaying this value on our browser screen. A single click on the screen updates the variable and also writes the new value to the real-time database.

Copyright ©2024 Educative, Inc. All rights reserved