JS Timer using AlpineJs with Carbon Format
Tags: laravel, alpinejs, javascript
Published: 2022-03-09 10:58:56

If you have used Carbon Class in PHP, then you might have heard about the method `Carbon::diffForHumans()`. It returns the difference between 2 dates in a Human Readable Form.

So if difference is less than 60 seconds, the output would be in seconds. If the difference is more than 60 seconds, the output would be in minutes. If the difference is more than 60 minutes, the output would be in hours and so on.

Recently I had to built a Timer in JS which should the elapsed Time in a similar manner. I choose to built the Timer using AlpineJS.

I choose to call my Component `moment` because I have been a big fan of `moment.js`. The Component had a prop of `seconds` which would hold the number of seconds that timer would need to display. 

```
<span x-data="moment">
</span>

<script>
    function moment() {
        return {
            seconds: 1,
        }
    }
</script>
```
Next I created an `init` method which would set the initial value of the timer.

```
<span x-data="moment" x-init="init(40)">
</span>

<script>
    function moment() {
        return {
            seconds: 1,
            init(seconds) {
                this.seconds = seconds;
            },
        }
    }
</script>
```
Next, within this init method, I would use `setInterval` to call a closure after each second. Within the closure, I would increment the value of `seconds` prop. I would also create an `interval` prop which I could use to close the Timer.

```
interval: "",
init(seconds) {
    this.seconds = seconds;
    this.interval = setInterval(() => {
        this.seconds++;
    }, 1000);
},
```

Next I will create a method to display the Timer, I will call it `getTimeElapsed` and use it as below:

```
<span x-data="moment" x-init="init(40)">
    <span x-text="getTimeElapsed"></span>
</span>

.
.
.
            getTimeElapsed() {
                return this.seconds;
            }
```

At this stage the Timer would be working well and it will increment after each second. Now, we would format the `getTimeElapsed` method so that it would return the data similar to Carbon method.

In order to do so, I created an `intervals` property like below:

```
    intervals: [
      { label: "hour", seconds: 3599 },
      { label: "minute", seconds: 59 },
      { label: "second", seconds: 1 }
    ],
```

And then I used this property within the `getTimeElapsed` as follows:

```
getTimeElapsed() {
    const interval = this.intervals.find((i) => i.seconds < this.seconds);
    const count = Math.floor(this.seconds / interval.seconds);
    return `${count} ${interval.label}${count !== 1 ? "s" : ""} ago`;
}
```

This will display the difference in seconds and as soon as the difference crosses 59 seconds, it would display the difference in minutes and so on. I only needed difference till hours so I only defined `interval` props till 3600. If you need to display days, you can define further.

My last requirement was to Stop the Timer as soon as it crossed 2 hours. So I used the following check in `getTimeElapsed`.

```
if (this.seconds > 7200) {
    clearInterval(this.interval);
}
```

The beauty of AlpineJS is that you can define multiple of these Components on your page and each will behave independently of each other. You can check the implementation at the [CodePen](https://codepen.io/100r0bh/pen/jOaQqmB).

Hope you have enjoyed this tutorial. For similar articles, you can follow me on [Twitter](https://twitter.com/TheLaravelDev)