How to build a datepicker with Angular, Bulma and Moment.js (part 3)

Giovanni Chiodi
4 min readApr 9, 2018

--

This is a “live” tutorial, you wont be able to follow it unless you went through part 1 and part 2.

Good morning. It rains, the lake is hidden by the mist, and I’m listening to something romantic. After all this is a date picker. And surely enough I have an OkCupid tab open. For debugging.

This is what we’ve got:

And the full code:

We need to grab the date on selection. The selection will give us a number. Hence we need to understand how to turn numbers in to dates. And then build a function dateFromNum that will take a number and return a date. Let’s see… oh, I love you Moment.js:

moment().date(number);

If we have a moment object we can mutate it to the date of a given day number with the date() method, passing indeed the day number as a parameter. In our case, if we want to transform the selected number in to a date:

const selectedDate = moment(navDate);
selectedDate.date(selectedNumber);

We don’t even have to check the validity of the number since we generated the numbers from the month directly. So here’s the dateFromNum function:

dateFromNum(num: number, referenceDate: any): any{
let returnDate = moment(referenceDate);
return returnDate.date(num);
}

For the moment we can also pass a referenceDate as I’m not sure we will use it only for our navDate. In fact, the first use case I see of this function is to make past days unavailable, as we decided they should be. If you noticed, we restricted the navigation to past months but past days within the current month still display as available.

For that, we can modify the isAvailable function (also getting rid of the random disabling of every 5th of the month):

isAvailable(num: number): boolean{
let dateToCheck = dateFromNum(num, navDate);
if(dateToCheck.isBefore(moment(), 'day')){
return true;
} else {
return false;
}
}

We used the isBefore() method which checks if a date is before another. We checked it against today (moment()), specifying we want the check to be made on a day basis (‘day’ option), so we don’t have to deal with eventual unexpected results due to hours and minutes (and milliseconds).

Cool, let’s code it!… Here it is:

And it works!!

Today is the 9th

Now we made all the checks we wanted on date availability, can easily and safely select a number, turn it in to a date, and store it in a selectedDate variable. Let’s start from the template. Where there seem to be a problem actually…

The Bulma Calendar css applies the nice ‘is-disabled’ class on the ‘calendar-date’ div, not on the ‘date-item’ button. This means that we disabled the days only visually, but they will still be available for selection through a click event. So we need to pass to the function handling the click the whole day object ({value: 3, available: true}) rather than just the number as I was imagining, and then check again if it’s available or not. This is not too bad.

Let’s add a click event and a function to handle the selection:

The selectedDay function (which populates the selectedDay variable):

And… it… works!!! This is the end result:

And this is the full code:

And it’s done, at least for what I personally have to do with it. But, it needs some adjustments in order to be more configurable and controlled from an outside parent component. Next steps would be:

  • Create a ‘option’ object which will be an Input property and will contain all the configurations, including callback functions which can be passed from outside
  • Adjust all the functions to work according to the options
  • Let the component ‘emit’ the selected date, and maybe a configurable callback too
  • Add extra visualization leveraging Bulma Calendar css

I’m not sure when I will have time for that... but soon, hopefully. You can follow the progress here on Github (or fork contribute etc.):

All in all, I didn’t think I could do it, but here it is. Thanks for reading, making the tutorial was really crucial in my motivation, hope you enjoyed it and ended up with something functional too!!

--

--