Building a Date Time Range Picker With Angular, Bulma, and Moment.JS

Mokshith Nath Pyla
The Startup
Published in
5 min readAug 13, 2020
Photo by Bich Tran from Pexels

Picking a date. Should be simple enough right? After multiple iterations of using the default HTML5 date-picker and various npm packages, the truth dawned upon me. Not quite. Although they work for their designated use cases, ultimately there isn’t one out there that fulfills them all. So, I rolled up my sleeves to build one from scratch. (with some help) Here’s how I did it.

Date Time Range Picker
Date Time Range Picker

Let me retrace my steps to explain how I built this brick by brick, date by date, month by month, year by… Okay you get the point. Lets go right to the beginning and get a peek of my process.

1. List out the Requirements

We need an intuitive date picker that is capable of checking the following boxes:

  • Allow picking a date
  • Provide option to include end date so as to allow picking start date as well as end date
  • Provide option to include time
  • Allow entering time in various formats (Essentially, we need a smart time picker)

Now that we’ve got the todos listed down. Lets roughly visualize how this component should ideally look like. Here’s an early illustration:

Rough Illustration

… Thank god for css.

Okay, going by our exquisite illustration. What we will need to put in place first, is a basic calendar that is navigable by months showing the year and days of the week.

2. Structuring The Data:

We need to design our data structure that will allow us to map days of each month. This grid like structure can be implemented in the following manner:

“Here obj is an entity that represents the day which we will later use to store custom key values that will indicate if the day is available, is selected and so on”

gridArr = {
"Jan": [obj, obj,...], // 31 objects
"Feb": [obj, obj, ...], // 28/29 objects
...
"Dec": [obj, obj, ...], // 31 objects
}

Only, that was the mistake I initially made. In trying to bring the mockups to life, it did not cross my head what would happen if we navigate across years.

So, we need another layer of restructuring.

gridArr = {
"2020": {
"Jan": [obj, obj,...], // 31 objects
"Feb": [obj, obj, ...], // 28/29 objects
...
"Dec": [obj, obj,...], // 31 objects
},
"2021": {
...
}}

3. Filling in the Gaps

In every calendar month, there are certain number of days that are grayed out or blank. Basically, only the days belonging to the current month matter to us. Using Moment.js, we can get the start/end day of the month and its corresponding day number of the week. So all the cells that appear before our starting day number and those that appear after our last day number, are empty or blank.

const firstDayDate = moment(currentDate).startOf('month');this.initialEmptyCells = firstDayDate.weekday();const lastDayDate = moment(currentDate).endOf('month');this.lastEmptyCells = 6 - lastDayDate.weekday();

4. User friendly Visualization:

Leveraging Moment.js and the css classes provided by Bulma, we map our gridArr to represent the calendar, highlighting today’s date, the selected start date, the selected end date and most importantly the range between the two.

Bulma CSS classes & usage

Beginning from the start date all the way up to the end date, we add a key to the objects of the gridArr (obj) called inRange and set the value to true for all the days that fall in between. We apply the calendar-range css class to all the objects whose inRange value is true.

5. Intuitive Behavior

To decide the behavior of the date time range picker, I analyzed multiple scenarios where multiple dates are picked and existing date-pickers to zero in on the best of the lot. For example, any flight ticket booking page that requires picking the arrival and departure dates and the date-pickers that popular project management tools use.

And from the culmination of the research, I arrived at the following:

Date Time Range Picker Behavior

We indicate which date (start or end) is being picked by providing the container box a blue shadow. And going beyond the limits of the selected date flips them. i.e While choosing an end date, if we pick a date before the start date, we assign that date to be the start date and our existing start date becomes the new end date. In a similar fashion, the same logic applies while picking the start date as well. I maintained two modes namely, ‘start’ and ‘end’ as an indicator of which date (start or end) is currently being picked.

Exception: What happens if we pick an end date equal to the start date? Or a a start date equal to the end date? We simply toggle the mode!

6. AM to the PM, PM to the AM funk

I mean, We need a smart time picker. One way would be to maintain a bunch of select drop-downs that have options ranging from 1–12 for hours, 0–60 for minutes and AM & PM for the time format. And there we have it, the ugliest time picker ever.

Okay. How about this? We take the entire field as an input text and handle all the possible ways that the user can enter the time. Sure. This should do for now. Note: For any invalid input to the time picker, we indicate with a red box shadow

Time Picker

7. Talk is cheap, here’s the code:

Parent Component:

Parent Component Template:

Date Time Range Picker Component:

datepicker.component.ts

Date Time Range Picker Template:

datepicker.component.html

Date Time Range Picker CSS:

datepicker.component.css

8. Some Dependencies:

Install Bulma and Moment.js:

npm install --save bulma moment

Launch your code editor, and as a first thing enable bulma css by adding this line “../node_modules/bulma/css/bulma.css” in the “styles” array in the angular-cli.json file.

To add a proper calendar style to our datepicker, we need to grab this code from GitHub and save it in a file called bulma-calendar.min.css within our src folder and then make it available by adding another line in our angular-cli.json:

.angular-cli.json

And we’re all set.

Head here to my GitHub to access the complete code.

Click Here to head to the tutorial that was greatly helpful in gathering the right tools to build this component.

And there we have it! A Date Time Range Picker capable of handling start and end dates along with the respective timestamps. There, now it’s simple!

--

--