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.
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.
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"};
You can easily customize these values to match the configuration of your specific project.
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 msgport 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.
To build an Elm application, we’ll define the Model
, View
, Update
and Subscriptions
in our Elm file.
Model
functionThis 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}
The count
holds our our integer value which we will initialize to 1.
View
functionThis 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.
-- Viewview : Model -> Html Msgview model =case model.count ofJust 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.
Subscription
functionTo 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
.
-- Subscriptionssubscriptions : Model -> Sub Msgsubscriptions 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.
Update
functionThe 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.
-- Updateupdate : Msg -> Model -> (Model, Cmd Msg)update msg model =case msg ofClick ->case model.count ofJust 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 ofJust 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.
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()); });
After executing the code, we get the output, as shown in the illustration below:
By simply clicking anywhere on the screen the score
variable is updated on Firebase, and the change is shown on our screen.
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.