Firebase x Axios x JS- Let's create a simple synchronized clicks counter
Tags: javascript, firebase, axios
Published: 2020-07-01 16:39:49

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/](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 .

```html
// 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>
```

```javascript
// 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();
});
```

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

```html
<!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>
```

![https://i.imgur.com/I87rap1.gif](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/](https://firebase.google.com/). Then, let's go to our console!

![https://i.imgur.com/E7FwGuP.png](https://i.imgur.com/E7FwGuP.png)

We can now add a new project

![https://i.imgur.com/wNd5jCT.png](https://i.imgur.com/wNd5jCT.png)

Let's name our project "my-counter"

![https://i.imgur.com/yKcviBN.png](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](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](https://i.imgur.com/UTpYxNu.png)

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

![https://i.imgur.com/jGJCiRr.png](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](https://i.imgur.com/buCiSB2.png)

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

- Your DB URL, on the top that should look like this: https://your-project-name-00000.firebaseio.com/. Copy that URL somewhere, we'll need that later.
- And our empty DB body 😇

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](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](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](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](https://github.com/axios/axios)".* In other words, you can use [HTTP Methods](https://www.restapitutorial.com/lessons/httpmethods.html) (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.

```html
<!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>
```

```javascript
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();**
```

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.

```javascript
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();
```

![https://i.imgur.com/92Kj87g.gif](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](https://i.imgur.com/R5Kg6Ss.png)

Then, let's updates the rules

```json
// old rules
{
  "rules": {
// Anyone can Create/Read/Update/Delete our database entries
    ".read": true,
    ".write": true
  }
}
```

```json
// 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"
      }
    }
  }
}
```

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 🤙