Add date range to NgbInputDatepicker input field
Using ElementRef
and ViewChild
to set the input value would work.
I mean not using ViewChild
with the Directive/Component( NgbInputDatepicker
), because all accessor to the element from the directive are private and I dont see how to change the input from there unless in _writeModelValue
method (line 363) , writeValue
call it, but it only update one date.
So the steps are:
- by using
ElementRef
andViewChild
to having the input element, - and
Renderer2
for setting its value (like the directive do) - and using
NgbDateParserFormatter
to format the model date - You just need to do this when date is selected, so in the method
onDateSelection
This is the main code, I'll add some comments:
HTML:
<input
#myRangeInput
class="form-control"
placeholder="mm/dd/yyyy"
name="dp"
[(ngModel)]="model"
ngbDatepicker
[dayTemplate]="t"
[autoClose]="false"
[displayMonths]="2"
[maxDate]="maxDate"
[minDate]="minDate"
>
<ng-template #t let-date="date" let-focused="focused">
<span class="custom-day"
[class.range]="isFrom(date) || isTo(date) || isInside(date) || isHovered(date)"
[class.faded]="isHovered(date) || isInside(date)"
(click)="onDateSelection(date)"
(mouseenter)="hoveredDate = date"
(mouseleave)="hoveredDate = null"
>
{{ date.day }}
</span>
</ng-template>
TYPESCRIPT:
import {Component, ViewChild, OnInit, ElementRef, Renderer2} from '@angular/core';
import {
NgbDatepicker,
NgbInputDatepicker,
NgbDateStruct,
NgbCalendar,
NgbDateAdapter,
NgbDateParserFormatter} from '@ng-bootstrap/ng-bootstrap';
...
export class NgbdDatepickerPopup implements OnInit{
...
@ViewChild('myRangeInput') myRangeInput: ElementRef;
constructor(element: ElementRef, private renderer: Renderer2, private _parserFormatter: NgbDateParserFormatter) { }
onDateSelection(date: NgbDateStruct) {
let parsed = ''; // initializing with empty string
if (!this.fromDate && !this.toDate) {
this.fromDate = date;
} else if (this.fromDate && !this.toDate && after(date, this.fromDate)) {
this.toDate = date;
this.input.close();
} else {
this.toDate = null;
this.fromDate = date;
}
if(this.fromDate) {
// if fromDate is set: add the first date
parsed += this._parserFormatter.format(this.fromDate);
}
if(this.toDate) {
// if toDate is set: add the second date with separator
parsed += ' - ' + this._parserFormatter.format(this.toDate);
}
// here we update the input value with the new parsed value
this.renderer.setProperty(this.myRangeInput.nativeElement, 'value', parsed);
}
And this is the working demo: https://stackblitz.com/edit/angular-skbpc8-maun8a
The above answer is correct and I would had made this a comment had I the required reputation but since I cant, here is a snippet of css you can add to styles.css to complete the functionality.
.ngb-dp-day.disabled[_ngcontent-c21], .ngb-dp-day.hidden[_ngcontent-c21] {
cursor: default;
color: #d0d0d0;
pointer-events: none;
-webkit-user-select: none; /* Chrome all / Safari all */
-moz-user-select: none; /* Firefox all */
-ms-user-select: none; /* IE 10+ */
user-select: none; /* Likely future */
}
This will make the disabled by min/maxDate or by markDisabled dates to look faded and unselectable.