How can I catch the Material Datepicker month pagination event?

前端 未结 4 624
天涯浪人
天涯浪人 2020-12-12 01:37

I would like to catch the event that comes from the month \"left\" and \"right\" selection buttons, but I couldn\'t find any documentation about it.

What ev

相关标签:
4条回答
  • 2020-12-12 02:08

    on the Template where:

    <mat-datepicker #picker (opened)="initEvents()"></mat-datepicker>
    

    add an event listener when the datepicker is open and add to the buttons the click event...

    TS:

    initEvents(): void {
    setTimeout(() => {
      const prev = document.querySelector('.mat-calendar-previous-button');
      const next = document.querySelector('.mat-calendar-next-button');
      prev.addEventListener('click', () => { // Previous Button
        console.log('Prev');
      });
      next.addEventListener('click', () => { // Next Button
        console.log('Prev');
      });
    
    }, 150);
    

    }

    Hope it works :)

    without the small delay, it will display u a null reference, anyway with the small delay it should work well, in any way there's a delay when the user clicks on that datepicker by the animation so..

    btw: it displays null because the event occurs before the element (our buttons) are in the DOM...

    EDIT: one more thing am this solution may not the best because ur register events every time the datepicker is opened, but its the best and the fastest way which i found, an a better way of doing that is by creating a custom header... but its a lot of codes to write.., u can check it on official docs if u want.

    0 讨论(0)
  • 2020-12-12 02:13

    the only way I've found is, (idea from onthecode) in open, check for querySelectorAll of the buttons. some like

    <mat-form-field>
      <input matInput [matDatepicker]="picker" placeholder="Choose a date">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker (opened)="openCalendar()">
      </mat-datepicker>
    </mat-form-field>
    
      constructor(private renderer: Renderer2) { }
      openCalendar() {
        setTimeout(() => {
          const buttons = document.querySelectorAll
          ('.mat-calendar-previous-button,.mat-calendar-next-button')
          if (buttons) {
            Array.from(buttons).forEach(button => {
              this.renderer.listen(button, "click", (event) => {
                console.log('Arrow button clicked')
              });
            })
          }
        })
      }
    

    see stackblitz

    0 讨论(0)
  • 2020-12-12 02:24

    Well, my another response is wrong, Let's go to take another aproach. Imagine we has a CustomTemplate Header. As we want that it's looks like the original DatePicker header we are copy the template of this that is in gitHub of angular, but we are change the functions in button next an prev, so it's like

    <div class="mat-calendar-header">
      <div class="mat-calendar-controls">
        <button mat-button type="button" class="mat-calendar-period-button"
                (click)="currentPeriodClicked()" [attr.aria-label]="periodButtonLabel"
                cdkAriaLive="polite">
          {{periodButtonText}}
          <div class="mat-calendar-arrow"
               [class.mat-calendar-invert]="calendar.currentView != 'month'"></div>
        </button>
    
        <div class="mat-calendar-spacer"></div>
    
        <ng-content></ng-content>
    
                    <!--see that we change previousClicked by customPrev-->
        <button mat-icon-button type="button" class="mat-calendar-previous-button"
                [disabled]="!previousEnabled()" (click)="customPrev()"
                [attr.aria-label]="prevButtonLabel">
        </button>
    
                    <!--see that we change nextClicked by customNext-->
        <button mat-icon-button type="button" class="mat-calendar-next-button"
                [disabled]="!nextEnabled()" (click)="customNext()"
                [attr.aria-label]="nextButtonLabel">
        </button>
      </div>
    </div>  
    

    Now we defined our customHeader extends from MatCalendarHeader

    export class ExampleHeader extends MatCalendarHeader<any> {
    
      /** Handles user clicks on the period label. */
      currentPeriodClicked(): void {
        this.calendar.currentView = this.calendar.currentView == 'month' ? 'multi-year' : 'month';
      }
    
      /** Handles user clicks on the previous button. */
      customPrev(): void {
        console.log(this.calendar.activeDate)
        this.previousClicked()
      }
    
      /** Handles user clicks on the next button. */
      customNext(): void {
        console.log(this.calendar.activeDate)
        this.nextClicked()
      }
    

    Then , just only say that use this ExampleHeader

    <mat-form-field>
      <mat-label>Custom calendar header</mat-label>
      <input matInput [matDatepicker]="picker">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker [calendarHeaderComponent]="exampleHeader"></mat-datepicker>
    </mat-form-field>
    

    See in stackblitz

    0 讨论(0)
  • 2020-12-12 02:30

    There's a work-around too that is use the dateClass

    @ViewChild('picker',{static:false}) calendar: MatDatepicker<any>;
      setClass() {
        return (date: any) => {
          if (date.getDate() == 1) this.changeMonth(
             {month:date.getMonth()+1,
              year:date.getFullYear()
              });
        };
      }
    
      changeMonth(date)
      {
        console.log(date)
      }
    

    where you has

     <mat-form-field>
      <mat-label>Choose a date</mat-label>
      <input matInput [matDatepicker]="picker">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker [dateClass]="setClass()"></mat-datepicker>
    </mat-form-field>
    

    See stackblitz

    Well, nobody has interest in know when the month change if he has no good reason. The typical reason is call to an API that return an array with "specials" days and show in the calendar.

    To change the aspect of this specials days we can think that we can use the own function dateClass but remember that we are looking for the days after the function is executed (*). So we need use Renderer2 to add the class.

    If the data we received is some like (see that "day" is a string)

      [
        {day:'2020-02-06',data:'one'},
        {day:'2020-02-16',data:'two'},
        {day:'2020-02-22',data:'three'}
      ]
    

    Our function changeMonth becomes like:

    changeMonth(date) {
        this.dataService.getData(date.month, date.year).subscribe(res => {
          setTimeout(() => {
            let elements = document.querySelectorAll(".calendar");
            if (elements && elements.length) {
              const cells = elements[0].querySelectorAll(".mat-calendar-body-cell");
              cells.forEach(x => {
                const date = new Date(x.getAttribute("aria-label"));
                const dateTxt =
                  date.getFullYear() +
                  "-" +
                  ("00" + (date.getMonth() + 1)).slice(-2) +
                  "-" +
                  ("00" + date.getDate()).slice(-2);
    
                if (res.find(x => x.day == dateTxt))
                {
                  this.renderer.addClass(x, "special");
                }
              });
            }
          });
        });
      }
    

    (*) we can also ask for the "special days" in ngOnInit and, then simple use the dateClass function

    0 讨论(0)
提交回复
热议问题