问题
I'm using ngx-botstrap BsDatepickerModule for my application form and I have a requirement to pick only a month. Does anyone know where I can find a solution? This issue has been raised almost a year ago and looks like it is highly demanded, so I conceal a hope to get an answer. This is what I would like to see after clicking a date selector button:
回答1:
I managed to solve this using the same bsDatepicker, with minimal effort
Component template:
<form class="container">
<input [(ngModel)]="modelDate" autocomplete="off" class="form-control" name="date" bsDatepicker [bsConfig]="{dateInputFormat: 'MM/YYYY'}" (onShown)="onOpenCalendar($event)">
Result: <p>{{modelDate}}</p>
</form>
Component code sample:
onOpenCalendar(container) {
container.monthSelectHandler = (event: any): void => {
container._store.dispatch(container._actions.select(event.date));
};
container.setViewMode('month');
}
Check working sample here https://stackblitz.com/edit/ngx-datepicker-month-picker-poc
回答2:
Sometime ago I make a month-year date picker based in ng-bootstrap ngbDropdownToggle (not in ngx-bootstrap, but I supouse the code must be similar in ngx-bootstrap
The code is in https://stackblitz.com/edit/angular-zs1rxp
The basic is using a DropDownToggle that show months or years
<div class="btn-group" ngbDropdown #calendarPanel="ngbDropdown">
<input type="text" class="form-control" id="data" name="data" [(ngModel)]="dataTxt" [placeholder]="mask" #item (input)="change(item.value)">
<button class="btn btn-outline-primary dropdown-toggle-split" ngbDropdownToggle>
<i class="fa fa-calendar" aria-hidden="true"></i>
</button>
<div ngbDropdownMenu class="dropdown-menu">
<div class="row">
<button class="btn btn-link col-4" (click)="addYear($event,-1)">
<span class="fa fa-chevron-left"></span>
</button>
<button *ngIf="!isyear" class="btn btn-link col-4" (click)="showYear($event,true)">{{data.year}}</button>
<button *ngIf="isyear" class="btn btn-link col-4" (click)="showYear($event,false)">{{incr+1}}-{{incr+10}}</button>
<button class="btn btn-link col-4" (click)="addYear($event,+1)">
<span class="fa fa-chevron-right"></span>
</button>
<div *ngFor="let month of months; let i = index; let first = first; let last = last" class="col-4" (click)="selectYearMonth($event,i)">
<div [ngClass]="{'select': !isyear?(i+1)==data.month:(i+incr)==data.year,'outrange':isyear && (first || last)}" class="card-body">
<span *ngIf="!isyear">{{month}}</span>
<span *ngIf="isyear">{{i+incr}}</span>
</div>
</div>
</div>
</div>
</div>
the "key" is show months (an array with the name of months) or i+incr, where incr is (year-year%10)-1
The .ts is complex because we make a custom form component
interface Idata {
month: number;
year: number;
}
@Component({
selector: 'month-date-picker',
templateUrl: './month-date-picker.component.html',
styleUrls: ['./month-date-picker.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MonthDatePickerComponent),
multi: true
}
]
})
export class MonthDatePickerComponent implements ControlValueAccessor {
data: Idata;
dataTxt: string;
separator: string;
monthFirst: boolean;
place: number;
isyear:boolean=false;
incr:number=0;
months: string[] = ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"];
// Allow the input to be disabled, and when it is make it somewhat transparent.
@Input() disabled = false;
@Input() mask = "mm-yyyy";
@ViewChild('calendarPanel') calendar: NgbDropdown;
constructor() {
this.separator = this.mask.replace(/m|y|M/gi, "");
this.monthFirst = this.mask.indexOf('y') > 0;
this.place = this.mask.indexOf(this.separator);
}
change(value: string) {
value=this.separator==" "?value.replace(/\.|-|\//," "):
this.separator=="/"?value.replace(/\.|-| /,"/"):
this.separator=="-"?value.replace(/\.| |\/ /,"-"):
value.replace(/.| |\/ /,"-");
let lastchar = value.substr(value.length - 1);
if (lastchar == this.separator && value.length <= this.place) {
if (this.monthFirst) {
value = "0" + value;
}
}
if (value.length > this.place && value.indexOf(this.separator) < 0) {
value = value.substr(0, value.length - 1) + this.separator + lastchar;
}
this.dataTxt = value;
let items = value.split(this.separator);
if (items.length == 2) {
let year = this.monthFirst ? items[1] : items[0];
let month = this.monthFirst ? items[0] : items[1];
let imonth = this.months.indexOf(month);
if ((imonth) < 0)
imonth = parseInt(month);
else
imonth = imonth + 1;
let iyear = parseInt(year);
if (iyear < 100)
iyear = iyear + 2000;
this.data = {
year: iyear,
month: imonth
}
this.incr=this.getIncr(this.data.year);
}
this.writeValue(this.data);
}
selectYearMonth($event,index:number)
{
if (this.isyear)
{
$event.stopPropagation();
this.data.year=index+this.incr;
this.dataTxt=this.formatData(this.data);
this.isyear=false;
this.incr=this.getIncr(this.data.year);
}
else{
this.data.month=index+1;
this.dataTxt=this.formatData(this.data);
}
}
showYear($event:any,show:boolean)
{
$event.stopPropagation();
this.isyear=!this.isyear;
}
addYear($event:any,incr:number)
{
$event.stopPropagation();
let year=this.isyear?this.data.year+10*incr:this.data.year+incr;
console.log(year);
this.data.year=year;
this.incr=this.getIncr(year);
this.dataTxt=this.formatData(this.data);
}
onChange = (data: Idata) => {
this.data = data;
this.dataTxt = this.monthFirst ? "" + data.month + this.separator + data.year :
"" + data.year + this.separator + data.month;
this.incr=this.getIncr(this.data.year);
};
getIncr(year:number):number
{
return (year-year%10)-1;
}
formatData(data:Idata):string
{
let monthTxt=data.month<10? "0"+data.month:"" + data.month;
return this.monthFirst ? monthTxt+ this.separator + data.year :
"" + data.year + this.separator + monthTxt
}
// Function to call when the input is touched (when a star is clicked).
onTouched = () => { };
writeValue(data: Idata): void {
this.data = data;
this.onChange(this.data)
}
// Allows Angular to register a function to call when the model (rating) changes.
// Save the function as a property to call later here.
registerOnChange(fn: (data: Idata) => void): void {
this.onChange = fn;
}
// Allows Angular to register a function to call when the input has been touched.
// Save the function as a property to call later here.
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
// Allows Angular to disable the input.
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
NOTE:Sorry, My code depending font-awesome and son't see in the stackbliz
回答3:
See the issue for featuring possible option #2627
回答4:
This request applied and implemented, it available in 3.1.3 ngx-bootstrap version This is a DEMO
And this is a CHANGELOG
来源:https://stackoverflow.com/questions/51200121/ngx-bootstrap-datepicker-option-to-pick-only-month-and-a-year