DEV Community

Cover image for Firebase x Axios x JS- Let's create a simple synchronized clicks counter
Florian
Florian

Posted on

Firebase x Axios x JS- Let's create a simple synchronized clicks counter

Let's create a JavaScript click counter that keep track of the clicks, thanks to Firebase Realtime Database!

You can see the live result here : https://jsfiddle.net/Icesofty/kz4u2rt9/3/

The Basics

First, we need some basic files : our entry point, index.html , and our script click-counter.js .

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Firebase & JS</title>
  </head>
  <body>
        <!-- The clickable button  -->
    <button id="btn">
      CLick Me!
    </button>
        <!-- The counter will be displayed here -->
    <h2 id="counter"></h2>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
// We save our button element into a variable
const btn = document.getElementById("btn");
// We save our counter element into a variable
const counterID = document.getElementById("counter");

// We start our counter at 0
let counter = 0;

// Everytime a user click on the button, we will call this function to display the counter
function updateCounter() {
  counterID.innerHTML = `${counter} visitors clicked on this button`;
}

// Everytime a user clicks on the button, we will increment the counter by one.
btn.addEventListener("click", function (e) {
  counter++;
  updateCounter();
});
Enter fullscreen mode Exit fullscreen mode

Let's add our script into our index.html file

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <!-- We add the script -->
    **<script src="./js/click-counter.js" defer></script>**
    <title>Firebase & JS</title>
  </head>
  <body>
    <button id="btn">
      CLick Me!
    </button>
    <h2 id="counter"></h2>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

https://i.imgur.com/I87rap1.gif

the result

We know have a super simple, but yet working click counter, cool!

But there is one main problem. The current state of the counter is not saved and will reset every time we reload the page. Also, the counter is not synchronizing with the visitors: This is a local counter.

Firebase

To keep track of the counter, we need to increment it every time a user clicks on it and store the updated state into a Database.

To do that, we'll use the Realtime Database from Firebase (Firebase is not a Database, Firebase is a set of ready to be deployed tools for your project). Realtime DB is a NoSQL type database that takes literally 5 minutes to set up. Values are stored in a JSON-like tree, which makes them really easy to read and manipulate.

First, we need to create an account at https://firebase.google.com/. Then, let's go to our console!

https://i.imgur.com/E7FwGuP.png

We can now add a new project

https://i.imgur.com/wNd5jCT.png

Let's name our project "my-counter"

https://i.imgur.com/yKcviBN.png

For this project, we can disable Google Analytics, we won't need it.

https://i.imgur.com/HTDqqLB.png

Hooray! Our Firebase project is now live and ready.

Welcome to the Dashboard. Here, you have access to all the tools provided by Firebase. We're going to create a database, so let's click on Database!

https://i.imgur.com/UTpYxNu.png

Firebase have two types of DB. Let's pick the Realtime Database.

https://i.imgur.com/jGJCiRr.png

For now, we'll choose the second option "Start Test Mode" to see if everything is running as excepted.

https://i.imgur.com/buCiSB2.png

We are now on our DB! You'll notice two things:

To keep track of the counter, we first need to create a child into our DB and create a key - value pair for the actual counter. Click on the '+'

https://i.imgur.com/SLt0F4y.png

For the project, I will name my child "my-online-counter" , don't enter any value since this is just a child, not the actual data. To create our counter value, let's click on '+' again.

https://i.imgur.com/bYg7M1z.png

This will create another child! I'll name it 'counter' and add a value of 0 as a starting value. Because, well, nobody clicked on our button yet😉

Once done, we can now click on the blue "add" button. And we're done with the Database... for now!

https://i.imgur.com/unsRrmM.png

Now that our database is ready, it's time to make some changes into our JS script:

First, we need to GET the data and display the value of the counter, to show the number of time the button has been clicked

Then, we need to UPDATE the counter if a user clicks on the button, and then refresh & display the updated counter.

To get and update the data, we are going to use Axios. Axios is a "Promise based HTTP client for the browser and node.js". In other words, you can use HTTP Methods (or CRUD operations) directly into your JS file.

Get the value

I want to display the number of times a visitor clicked on the button when the web page is displayed.

First, we need to add Axios into our index.html file,

then we'll add the axios.get() method into our JS file.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <!-- We add axios to our index.html, **BEFORE** our script -->
    **<script
      src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"
      defer
    ></script>**
    <script src="./js/click-counter.js" defer></script>
    <title>Firebase & JS</title>
  </head>
  <body>
    <button id="btn" style="margin-top: 5rem;">
      CLick Me!
    </button>
    <h2 id="counter"></h2>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
const btn = document.getElementById("btn");
const counterID = document.getElementById("counter");

// Let's save our Firebase Realtime DB URL into a variable
**const firebase = "https://my-counter-5a9a7.firebaseio.com/";**

// Because we are fetching the current counter state from a Database,
// We don't need to start the counter at 0. 
// let counter = 0;

// We want to fetch and display the current state
// of the counter every time someone visits our website.
**function get() {**
    // We want the data from the child we created, so let's concat it into our URL
    // Note that every endpoint needs .json at the end!
  **axios.get(firebase + "my-online-counter.json").then((response) => {**
    // Once the connection made to the Database, we can use the reponse to update the counter
    **counter = response.data.counter;**
    // Once the coutner updated, we can display the current counter state.
    **updateCounter();
  });
}**

function updateCounter() {
  counterID.innerHTML = `${counter} visitors clicked on this button`;
}

btn.addEventListener("click", function (e) {
  counter++;
  updateCounter();
});

// We call the get() function everytime a user launch the script
**get();**
Enter fullscreen mode Exit fullscreen mode

We can now fetch the data from our DB and display the result directly into the webpage. But there is still a problem: the counter is still updating only on our local machine. 🤔

We need to UPDATE the counter in our DB.

Update the value

Now, I want to update the value of the counter when someone click on the button, and reload the counter displayed on the page.

For that, we need to add the axios.put() method into our JS file.

const btn = document.getElementById("btn");
const counterID = document.getElementById("counter");

const firebase = "https://my-counter-5a9a7.firebaseio.com/";

function get() {
  axios.get(firebase + "my-online-counter.json").then((response) => {
    counter = response.data.counter;
    updateCounter();
  });
}

function updateCounter() {
  counterID.innerHTML = `${counter} visitors clicked on this button`;
}

// Everytime a user clicks on the button, 
// we want to Update the counter into the database
**btn.addEventListener("click", function (e) {
  axios**
        // First, we need to reach our DB
    **.put(firebase + "my-online-counter.json", {**
            // Then, we needs to specify the new data for my-online-counter
****      // In our case, we simply increment the counter into the DB by one.
      **counter: counter + 1
    })
    .then(() => {**
      // Once it's done, we call the get() function again. 
            //To display the updated counter.
      **get();
    })**
    // If there is an error, we can log it.
    **.catch((error) => console.log(error));
});**

get();
Enter fullscreen mode Exit fullscreen mode

https://i.imgur.com/92Kj87g.gif

Hooray! Our project is now running as expected. We can fetch the data from our DB and increment the counter value in our DB when we click on it.

But there is one main security issue. Our Realtime Database rules allow everyone to Red and Write into our Database! So literally anybody can Delete our database entries and increase or decrease our counter by any value!

Updating our Rules

To avoid such a scenario, we needs to update our DB rules.

First, let's go to the rules tab.

https://i.imgur.com/R5Kg6Ss.png

Then, let's updates the rules

// old rules
{
  "rules": {
// Anyone can Create/Read/Update/Delete our database entries
    ".read": true,
    ".write": true
  }
}
Enter fullscreen mode Exit fullscreen mode
// New rules
{
  "rules": {
        // We set the rule for our child
    "my-online-counter": {
            // We allow everybody to READ the data
      ".read": true,
            // We only allow updates on existing data & we don't allow creating new data
      ".write": "data.exists() && newData.exists()",
      "counter": {
                // To validate our counter update, 
                // and avoid decrementing the value or incrementing more than +1,
                // the data updated needs to be equal to the actual data + 1
        ".validate": "newData.val() == data.val() + 1"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

And we are done! We know have a fully working click counter in vanilla JS, thanks to Axios and the Realtime Database by Firebase. Hope you enjoyed my first article,

Cheers 🤙

Latest comments (1)

Collapse
 
bagera profile image
Victor Wihlborg

Why do you use axios and not just the firebase SDK? It would give you real time updates and it just seems weird using a real-time db without the real-time aspect.