How to customise an Angular Calendar to be vertically scrollable

888 views Asked by At

I have tried several calendars from npm, but haven't found a calendar that can be vertically scrollable, all the months should be rendered while the user scrolls the container.

Below is the screenshot of what exactly I need to develop.

1

There are 1 answers

0
Eliseo On

Makes a calendar it's not dificult, see, e.g. this SO

If you create a calendarComponent with this code

days:any[]
months=['ene','feb','mar','abr','may','jun','jul','ago','sep','oct','nov','dic']
weekdays=['Lu','Ma','Mi','Ju','Vi','Sa','Do']
@Input() set year(value:number)
{
  this._year=value;
  if (this._month)
    this.days=this.generateDays(this._year,this._month)
}
@Input() set month(value:number)
{
  this._month=value;
  if (this._year)
    this.days=this.generateDays(this._year,this._month)
}
private generateDays(year:number,month:number)
{
...
}

You can write some like

 <app-calendar [year]="year" [month]="month"></app-calendar>

Now you can using uin a scroll infinite using cdk-virtual-scroll-viewport (see, e.g. this link about this

So, our component can be like

<cdk-virtual-scroll-viewport #scroller itemSize="72" class="content">
  <ng-container *cdkVirtualFor="let item of items">
        <app-calendar [year]="item.year" [month]="item.month"></app-calendar>
  </ng-container>
</cdk-virtual-scroll-viewport>

where you has

  items:{year:number,month:number}[]=[]
  days: any[];
  ngOnInit()
  {
    this.fetchMore();
    this.scroller.elementScrolled().pipe(
      map(() => this.scroller.measureScrollOffset('bottom')),
      pairwise(),
      filter(([y1, y2]) => (y2 < y1 && y2 < 140)),
      throttleTime(200)
    ).subscribe(() => {
      this.ngZone.run(() => {
        this.fetchMore();
      })
    }
    );
  }
  fetchMore(): void {
    this.items=[...this.items,...[0,1,2,3,4,5,6].map(x=>this.incrementMonth(1))]
  }
  
  incrementMonth(increment) {
    const month =
      this.month + increment == 13
        ? 1
        : this.month + increment == 0
        ? 1
        : this.month + increment;
    this.year =
      this.month + increment == 13
        ? this.year + 1
        : this.month + increment == 0
        ? this.year - 1
        : this.year;
    this.month = month;
    return {year:this.year,month:this.month}
  }

You can see in this stackblitz

TO DO: not hardcode the month names, add a "click" to selected the day and beauty using .css