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.
Free Resources