A date picker so easy, you won’t believe it.



For a project that relied heavily on dates and a date picker we decided that instead of using a 3rd party calendar tool and date picker that we should make our own.

So I set off on the fun adventure of writing a date picker in angular 2 (or whatever we are supposed to call it these days.)

Layers:

In an attempt to make the date picker easier to test multiple components were created:


Layer 0 — The Grid

For better or worse, I decided to do a large chunk of the rendering outside of the normal bindings/change detection mechanisms. Coming from Angular 1 this was imperative as having this many bindings/repeats would have been detrimental to performance. It may not have mattered with Angular 2, I did it anyway.

Doing it the right way: In angular 2 you shouldn’t use jQuery, at least if you want to be compatible with universal apps. I decided to try and follow the rules. So I used the renderer.

Spoiler Alert:

Apparently [Experimental] means something

It worked, for a version or two, and maybe would have worked in a future version, but break me once, and you’re out. The renderer is a good idea and will be nice when its ready for prime time. If anything to make those jQuery nay-sayers stop telling me I shouldn’t use jQuery.

It also turns out that if you use the renderer or jQuery, you lose style encapsulation. In this case I didn’t mind, I wanted my style to be easily changed by other apps. But it is something to remember.

p.s.

If you ever need to create a calendar, iterating over a calendar object is the easiest way to do it.

while (d.month() === date.month()) {
//do something
d.date(d.date() + 1);
}

Layer — 1: The calendar.

The calendar layer takes the grid and controls what month is rendered. It is also where the month and year selection logic takes place. Nothing too exciting here, but a picture for good measure.

Pictures are fun.

Layer — 2 & Layer — 3: The datpicker and dualpicker

We need two styles of date pickers. I didn’t want my date picker to look like this:

if (mode === 'dual') {
//blah
} else {
//blah
}

So I opted to repeat some code, not that much, and have two separate wrappers.

Date picker has a single instance of the calendar.

Dual picker has two instances, which it always keeps in sync. The easiest way I found to keep them in sync was to only ever edit one calendar (in this case always the first), and have a function that modified the other date +/- a month.

The special thing about both of these modules is I used transclusion to allow me to create a component for an input, e.g.

<ct-date-picker [(date)]="date1" zIndex="100">
<input #date class="form-control" />
</ct-date-picker>

I then used the @ContentChild notation to access the input

@ContentChild('date') input: ElementRef;

This works pretty well. It allows the component using the date picker to continue to have control over the input, mostly for styling, etc. The <ct-date-picker></ct-date-picker> element does not affect the flow/styling of other components.

This article: http://orizens.com/wp/topics/lessons-learned-from-creating-a-typeahead-with-rxjs-and-angular-2/ did something similar, but they used the createEmbeededView method. This worked in their case, but in mine it prevented the @ViewChild from working preventing me from accessing the calendar/grid components. In addition its hard to follow what code is for what level of the component. At least in my case transclusion worked better.


To Do: There is still work to be done to make the datepicker configurable and to document those configurations. In the meantime, you can check out the code here:

https://github.com/Centeva/ngx-datepicker

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.