bm-datepicker
v1.0.10
Published
A sweet, stylish and fast datepicker for Angular. Developed for developers who want full control over the stylesheet and patterns. Can be used within a formgroup or as a standalone input with a standalone callback output.
Downloads
5
Maintainers
Readme
Bookmaker Datepicker for Angular
A sweet, stylish and fast datepicker for Angular. Developed for developers who want full control over the stylesheet and patterns. Can be used within a formgroup or as a standalone input with a standalone callback output.
Notice
This application requires Angular version 15.1.0 or newer to work correctly.
Installation
npm i bm-datepicker
Import module in app.module.ts
:
import { BmDatepickerModule } from 'bm-datepicker';
imports: [
BmDatepickerModule,
...
],
If you have an old version
v.1.0.2 - 1.0.4: (Deprected)
v.1.0.1
import { BmDatepickerModule } from "bm-datepicker";
Usage:
<bm-datepicker></bm-datepicker>
Formbuilder, evaluations, callbacks and error handling
Is it possible to connect Bookmaker to my Formbuilder?
Yes it is. Use formGroupInput
to connect to your formgroup and formControlNameInput
to set a control name.
<form [formGroup]="generatedFormGroup" (submit)="submitForm()">
<bm-datepicker [formGroupInput]="generatedFormGroup" formControlNameInput="dateFrom"> </bm-datepicker>
</form>
If you need to pre-define a date, you can do it in the component.
this.generatedFormGroup = this.formBuilder.group({
dateFrom: ["24-02-2023"],
});
Note! If you don't need Formbuilder at all, then remove both formGroupInput
and formControlNameInput
, otherwise you will get an error.
You will then need the calendarOutput
to fetch the callback event:
<bm-datepicker (calendarOutput)="calendarToOutput($event)"></bm-datepicker>
Can I use Formbuilder Validators?
Of course. Put you validation requirements in you component or service. Bookmaker will handle it via the formControlNameInput
you gave it.
How do I handle validated errors and error messages?
You can add the error messages below the Bookmaker and reference to the input field via the FormControllName. In component:
this.generatedFormGroup = this.formBuilder.group({
dateFrom: ["", Validators.required],
});
In HTML:
<p *ngIf="generatedFormGroup.get('dateFrom')?.errors?.['required']">This field is required</p>
There is a build in invalid
handler, that can be used as an evaluator connected to the entire form (if the input field is in a formgroup). This handler will be activated when the date don't follow the selected pattern
.
<button type="submit" [disabled]="generatedFormGroup.invalid">Submit form</button>
Use the errorMessage
option to show an error message of your choice, underneath the input field, when the date don't follow the selected pattern
.
<bm-datepicker errorMessage="The field is invalid"></bm-datepicker>
What if I want a different format of the input field, can I change it?
Yes, you can! Use the pattern
option to change format. The pattern is using lowercase letters for year, month and day.
<bm-datepicker pattern="mm/dd/yy"></bm-datepicker>
The default format is yyyy-mm-dd
and do not need the pattern to be written out.
The available patterns are... Have it your way! yyyy.mm-dd, dd/yyyy mm, mm/dd-yy - everything goes! The restrictions are
- The dividers can only be space
.
, forward slash/
or dash-
. - Days and months must two letters (mm) and (dd).
- Year can be either two letters (yy) or four letters (yyyy).
Can I use the input field to change the date?
Yes, you can!
The Bookmaker will accept changes as long as it follows the pattern
.
You can either pick a date from the calendar or fill it in manually.
The formated date will be presented in the input field and can be used via selected formControlNameInput
or used from the callback calendarOutput
.
Can I lock input field against manually changes?
Yes. You can lock the field with the [readonly]
option (and it must be inside square brackets []
). This option must have value of true
to work. Default value is always false
and do not need this option.
<bm-datepicker [readonly]="true"></bm-datepicker>
I don't use Formbuilder, can I get a callback response from Bookmaker?
You can use calendarOutput
to hook up to a response function of your own. The response value is the same as selected pattern. Default pattern is yyyy-mm-dd
.
Make a function in the same component as the Bookmaker to fetch the event value from the calendarOutput
.
<bm-datepicker (calendarOutput)="calendarToOutput($event)"></bm-datepicker>
Can I get a ISO-standard date callback?
There is an option to fetch an ISO-standard formatted date like Sat Feb 11 2023 01:00:00 GMT+0100
. Use the isoCalendarOutput
in those cases.
Read more about handling data below "Date handling, double calendars and advanced callbacks"
<bm-datepicker (isoCalendarOutput)="isoOutput($event)"></bm-datepicker>
Names, labels and texts
Hey, I want to change the label! Can I do that?
Use the label
option to change the text.
<bm-datepicker label="Date from"></bm-datepicker>
What about the placeholder, can I change that too?
Use the placeholder
option to change the text. The default value is "Pick a date".
<bm-datepicker placeholder="Pick a date"></bm-datepicker>
How I change the name of the Weekdays?
Bookmaker comes with a default array of the names in english. Use it to change it to a language of your choice. Connect it to weekdays
option.
In the HTML:
<bm-datepicker [weekdays]="weekdays"></bm-datepicker>
In the component:
weekdays = ['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'];
Can I change the week to start on a Sunday?
Yes! Use the [isSunday]
option (and it must be inside square brackets []
).
<bm-datepicker [isSunday]="true"></bm-datepicker>
How I change the name of the Months name?
Bookmaker comes with a default array of the names in english. Use it to change it to a language of your choice. Connect it to months
option.
In the HTML:
<bm-datepicker [months]="months"></bm-datepicker>
In the component:
months = [
'January', 'February', 'March', 'April',
'May', 'June', 'July', 'August',
'September', 'October', 'November', 'December'
];
Styles, icons and animations
Can I change the animations?
You can't change the toggle effect, but you change when it happens. You can use the [manualClose]
option to have the calendar open until you click on the open/close icon.
<bm-datepicker [manualClose]="true"></bm-datepicker>
Note! The toggle effect will occure after manually changes in the input field. This is needed to update the calender correctly and can't be turned off.
Can I change placement of the datepicker and input field?
Sorry, not yet. Officially. (Maybe if you hack the stylesheet - if so - let me know about it) :-)
I want a different calendar button icon. How do I change that (even if the default icon is quite fancy)?
Bookmaker have a default calendar icon. If you want to use your own, you can add it inside the Bookmaker.
The default size i maximum 20px, but if you want bigger button, you should also change the size in the .bm-toggle-button
style
<bm-datepicker>
<ng-icon name="akarCalendar" size="16px" color="white"></ng-icon>
</bm-datepicker>
Can I change the stylesheet?
You can change everything in Bookmaker. That's the beauty. It is a list of styles, but hey, you are a developer, aren't you? You can use the stylesheet to change parts or everything, it's up to you. Treat it as an usual stylesheet in SCSS. This is an overview of all elements, but you can concentrate it and put togther elements as you wish.
Use styleSheet
option to do the changes, and formControlNameInput
to make an individual stylesheet:
In the HTML:
<bm-datepicker formControlNameInput="dateFrom" [styleSheet]="styles"> <bm-datepicker></bm-datepicker></bm-datepicker>
In the component:
styles = `
p.bm-paragraph{
font-family:"Poppins", Verdana, sans-serif;
color: #000;
margin:0;
padding:0;
}
input.bm-date-input{
font-family:"Poppins", Verdana, sans-serif;
color: #000;
margin:0;
display:flex;
flex:1;
height:40px;
border-radius: 9999px;
padding: 3px 0 3px 20px;
border: 1px solid rgb(195, 195, 195)
}
label.bm-label{
font-family:"Poppins", Verdana, sans-serif;
color: #000;
margin:0;
padding:0;
font-size: .9rem;
font-weight: 500;
margin-left:15px;
}
.bm-date-input-wrapper{
position:relative;
width: 100%;
display:flex;
flex-direction:row;
align-items: center;
}
.bm-date-input-wrapper input[readonly] {
cursor: default !important;
background: rgb(245,245,245);
}
.bm-toggle-button{
position:absolute;
right:5px;
width:30px;
height:30px;
display:flex;
align-items:center;
justify-content:center;
background-color:rgb(0, 153, 235);
border: 1px solid rgb(0, 153, 235);
border-radius: 9999px;
transition:.5s
}
.bm-toggle-button:hover{
background-color: rgb(0, 131, 202);
cursor:pointer;
color:fff;
border: 1px solid rgb(0, 131, 202)
}
.bm-table{
width:100%;
background-color:#f5f5f5;
overflow: hidden;
padding:16px;
display:flex;
flex-direction: column;
border-radius: 8px;
box-shadow: 0 0 0.125rem 0 rgba(0,0,0,0.08), 0 0.125rem 0.75rem 0 rgba(0,0,0,0.24);
box-sizing:border-box;
}
.bm-tr{
display:flex;
flex:1;
justify-content:space-between;
align-items:center;
flex-direction: row;
}
.bm-th{
display:flex;
flex:1;
justify-content:center;
align-items:center;
flex-direction:row;
}
.bm-td{
display:flex;
flex:1;
justify-content:center;
align-items: center;
}
.bm-td-empty{
display:flex;
flex:1;
justify-content:center;
align-items: center;
}
.bm-td-empty .bm-td-inner-empty{
height:30px;
width:30px;
margin:2px;
}
.bm-td-inner{
height:30px;
width:30px;
margin:2px;
display:flex;
justify-content:center;
align-items: center;
border-radius:9999px;
transition: .4s;
border: 1px solid #f5f5f5;
}
.bm-td-inner:hover{
background-color: rgb(0, 131, 202);
cursor:pointer;
border: 1px solid rgb(0, 131, 202)
}
.bm-td-selected-day{
background-color: rgb(0, 153, 235);
cursor:pointer;
border: 1px solid rgb(0, 153, 235)
}
.bm-td-inner:hover p{color:#fff !important}
.bm-td-selected-day p{color:#fff !important}
.bm-th p{
font-size: .9rem;
font-weight: 500;
}
.bm-td-inner p{
font-size: .8rem;
font-weight: 300;
}
.bm-daylabels-wrapper{margin-bottom: 20px}
.bm-year-month-title {
display:flex;
flex: 5;
justify-content: center;
align-items: center;
flex-direction: column;
margin-bottom: 10px
}
.bm-year-month-title p.bm-month-title{
font-size: 1.5rem;
font-weight: 600;
margin-top: -8px
}
.bm-td-current-day{border: 1px solid rgb(0, 202, 101)}
.bm-td-lock-day{
pointer-events:none;
background: repeating-linear-gradient(-55deg,rgb(200, 200, 200), rgb(200, 200, 200) 2px,rgba(0,0,0,0) 2px, rgba(0,0,0,0) 4px);
border: 1px solid rgb(200, 200, 200)
}
.bm-arrow {
border: solid #000;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
}
.bm-td-inner:hover .bm-arrow{
border-color:white;
border-width: 0 3px 3px 0;
}
.bm-arrow-right {transform: rotate(-45deg);}
.bm-arrow-left {transform: rotate(135deg);}
.bm-weekend {color: #ff0000 !important}
.bm-error-message {
padding: 8px 16px 20px 16px;
}
.bm-error-message p{
color: #ff0000;
font-size: .8rem;
}
`;
There is a reference to the font "Poppins" in the stylesheet, but I only get Verdana?
To handle external fonts in Bookmaker, you need to have them globally in your Angular project. Use the link below in your root index.html
to get Poppins fontstyle:
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700;800&display=swap" rel="stylesheet" />
Date handling, double calendars and advanced callbacks
What is the default behavior?
The default behavior is to lock dates before current date. Current day is indicated with a green border. Selected date have blue background (if you don't change the stylesheet...)
<bm-datepicker></bm-datepicker>
How do I pre-define my own selected date?
You must use pattern
and selectedDate
options. Default pattern is yyyy-mm-dd
. If you're using this, you don't need to add this option, only selectedDate
.
It is important that selectedDate
uses the same pattern as pattern
.
<bm-datepicker pattern="dd-mm-yyyy" selectedDate="24-02-2023"></bm-datepicker>
If you want a dynamic date from the component, you can wrap the option name inside square brackets []
selectedDateValue="24-02-2023"
And add square brackets around the option [selectedDate]
.
<bm-datepicker pattern="dd-mm-yyyy" [selectedDate]="selectedDateValue"></bm-datepicker>
Note! The option selectedDate
overrides the default settings. If only selectedDate
is used without lockDateBefore
or lockDateAfter
, all dates are unlocked.
Can I lock dates before or after a current or a pre-defined date?
If you want to define your own lockings you can use the lockDateBefore
or lockDateAfter
options or use [lockDateBefore]
or [lockDateAfter]
for dynamic values.
It is important that lockDateBefore
and lockDateAfter
uses the same pattern as pattern
.
<bm-datepicker pattern="dd-mm-yyyy" lockDateBefore="24-02-2023"></bm-datepicker> <bm-datepicker pattern="dd-mm-yyyy" lockDateAfter="24-02-2023"></bm-datepicker>
You can either combine both lockDateBefore
and lockDateAfter
to limit the input range.
<bm-datepicker pattern="dd-mm-yyyy" lockDateBefore="20-02-2023" lockDateAfter="24-02-2023"></bm-datepicker>
Or you can add lockDateAfter
with selectedDate
if you need all dates before the lockDateAfter
.
<bm-datepicker pattern="dd-mm-yyyy" selectedDate="24-02-2023" lockDateAfter="24-02-2023"></bm-datepicker>
Or add all three and get a limit input range and a pre-selected date.
<bm-datepicker pattern="dd-mm-yyyy" selectedDate="24-02-2023" lockDateBefore="20-02-2023" lockDateAfter="24-02-2023"></bm-datepicker>
I want two datepickers - like "From Date" and "To Date", is that possible?
Of course! This is not a tiny lite version! This is the real deal! I assume that you have read through the documentation, because this tutorial needs some basic knownledge.
In this tutorial you will learn how to use two datepickers - a "From Date" and a "To Date".
The "From Date" will be responsable for locking lockDateBefore
inside "To Date" and the "To Date" will be responsable for locking lockDateAfter
inside "From Date".
Why?
Because it will prevent "From Date" to be selected later than "To Date" and vice versa.
Also - "From Date" will be locked before current date.
1. Set up the HTML
It is important to use square brackets []
though the values will be dynamic.
There will also need the callback function calendarOutput
that will be used in the component.
<bm-datepicker label="From Date" pattern="dd-mm-yyyy" [lockDateAfter]="lockDateAfterValue" [selectedDate]="selectedFromDateValue" (calendarOutput)="lockDateBefore($event)"></bm-datepicker> <bm-datepicker label="To Date" pattern="dd-mm-yyyy" [lockDateBefore]="lockDateBeforeValue" [selectedDate]="selectedToDateValue" (calendarOutput)="lockDateAfter($event)"></bm-datepicker>
2. Set up the component
In the component we need variables to hold the dates and functions to receive callbacks from the datepicker.
lockDateAfterValue: string = ""
lockDateBeforeValue: string = ""
selectedFromDateValue: string = ""
selectedToDateValue: string = ""
lockDateBefore(event:any){
this.lockDateBeforeValue = event.selectedDate
}
lockDateAfter(event:any){
this.lockDateAfterValue = event.selectedDate
}
3. Pre-define dates
You can also pre-define dates from, for example, a database. Use the variables in the component to set values:
lockDateAfterValue: string = "24-02-2023";
lockDateBeforeValue: string = "15-02-2023";
selectedFromDateValue: string = "24-02-2023";
selectedToDateValue: string = "20-02-2023";
4. Lock both calendars from current date
So this works fine. But what about limit the before date to current date in both calendars?
The "To Date" calendar is just fine, as it is, but if we use the dynamic option of [lockDateBefore]
inside the "From Date"...
<bm-datepicker label="From Date" pattern="dd-mm-yyyy" [lockDateAfter]="lockDateAfterValue" [lockDateBefore]="lockDateBeforeValue" [selectedDate]="selectedFromDateValue" (calendarOutput)="lockDateBefore($event)"></bm-datepicker>
...There will only be trouble. The problem is that the value will change everytime everytime we select a new date. We can always select forward, but never backwards. How to solve this - it is simple. Add a new variable in the component that won't be updated at all:
constantLockDateBeforeValue: string = "23-02-2023";
And add it to the [lockDateBefore]
in "From Date":
<bm-datepicker label="From Date" pattern="dd-mm-yyyy" [lockDateBefore]="constantLockDateBeforeValue" [lockDateAfter]="lockDateAfterValue" [selectedDate]="selectedFromDateValue" (calendarOutput)="lockDateBefore($event)"></bm-datepicker> <bm-datepicker label="To Date" pattern="dd-mm-yyyy" [lockDateBefore]="lockDateBeforeValue" [selectedDate]="selectedToDateValue" (calendarOutput)="lockDateAfter($event)"></bm-datepicker>
Done!
5. Test, tweak and test again!
That's it! Now it's up to you! Good luck!
Author
Steffo Dimfelt [email protected]
Version list
- 1.0.10: Adjust stylesheet
- 1.0.8: Adjust locked days and selected date