Angular Material Datepicker with Range Selection

后端 未结 3 1679
刺人心
刺人心 2021-01-24 23:35

I\'m using angular 8 and I wanted implement a datepicker with daterage highlighted: enter image description here I was looking for some package like this one: https://www.npmjs

相关标签:
3条回答
  • 2021-01-25 00:02

    In material date picker you can define max and min values.

    For example:

    example.hml <input matInput [min]="minValue" [max]="maxValue" [matDatepicker]="picker" formControlName="name"/> <mat-datepicker #voltageToDatePiker [startAt]="tomorrow"></mat-datepicker>

    example.ts minValue = new Date(); maxValue = new Date();

    0 讨论(0)
  • 2021-01-25 00:03

    IMPORTANT UPDATE, My good!! google is plenty full of controls like mine! (remember: Google is my friend, google is my friend...)

    I'm making a datePicker range in this stackblitz, i'll try to explain after

    Update I improve the stackblitz and a brief explanation

    There are a point important with the mat-date-picker that it's not possible create a day-template. So it's necesary use Renderer2 to add listener, add classes or remove classes. I need use document.querySelectorAll as it's show in this another SO

    The idea is, with the cells selected create an array of object

    {
       date: //will be a getTime of the date,
       element: //will be the nativeElement x,
       change: //a boolean to indicate this cell has an aditional class
       x.listen: //the listener added to allow us remove the listener
    }
    

    And a function who help us to add/remove class acording two variables: this._dateTo and another variable that will be this._dateFrom or another one (early we discovered why)

      redrawCells(timeTo: number) {
        timeTo = timeTo || this._dateTo;
        if (timeTo<this._dateFrom)
          timeTo=this._dateFrom
        this.cells.forEach(x => {
          const change = x.date >= this._dateFrom && x.date <= timeTo;
          if (change || x.change) {
            x.change = change;
            const addInside = x.change ? "addClass" : "removeClass";
            const addFrom = x.date == this._dateFrom? "addClass":
                            x.date == timeTo && this._dateFrom==timeTo? "addClass":
                            "removeClass";
            const addTo = x.date == timeTo? "addClass": 
                          x.date == this._dateFrom && this._dateFrom==timeTo? "addClass":
                            "removeClass";
    
            this.renderer[addInside](x.element, "inside");
            this.renderer[addFrom](x.element, "from");
            this.renderer[addTo](x.element, "to");
          }
        });
      }
    

    A new function setCell will be who manage the td to add/remove listener of mouse over. It's necesary enclosed in a setTimeout because we call this function before the calendar is drawed

      setCells() {
        setTimeout(() => {
          if (this.cells) {
            this.cells.forEach(x => {
              x.listen();  //<---remove the listener
            });
          }
          this.dateOver = null;
          //get the elements
          let elements = document.querySelectorAll(".calendar");
          if (!elements || elements.length == 0) return;
          const cells = elements[0].querySelectorAll(".mat-calendar-body-cell");
          this.cells = [];
          //with each element we fill our array "this.cells"
          cells.forEach((x, index) => {
            const date = new Date(x.getAttribute("aria-label"));
            const time=new Date(date.getFullYear() +"-" +(date.getMonth() + 1) +
                  "-" +date.getDate()).getTime()
    
            this.cells.push({
              date: time,
              element: x,
              change:time>=this._dateFrom && time<=this._dateTo
            });
          });
          this.cells.forEach(x => {
            if (!x.listen) {
              //we add a listener "mouseover"
              x.listen = this.renderer.listen(x.element, "mouseover", () => {
                if (!this._dateTo && this.dateOver != x.date) {
                  this.dateOver = x.date;
                  this.redrawCells(this.dateOver); //who call to redrawCells
                }
              });
            }
          });
        });
      }
    

    Well, the rest of function necesary to parse and format a date and open a mat-calendar using a mat-menu is from this another SO. In this last SO, the calendar not close, so, we can use to force two clicks to get a dateFrom and a dateTo

      select(date: any) {
        date = new Date(
          date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate()
        );
        if (
          !this.from.value ||
          (this.from.value && this.to.value) ||
          this._dateFrom > date.getTime()
        ) {
          this.dateFrom = date;
          this.dateTo = null;
          this.redrawCells(date.getTime());
        } else {
          this.dateTo = date;
          this.trigger.closeMenu();
        }
      }
    

    I like create a mat custom component. This allow us use the component in a mat-form-field, some like

    <mat-form-field class="full-width" >
      <mat-label>Select dates</mat-label>
      <date-picker-range [formControl]="control" placeholder="DD/MM/YYYY"  ></date-picker-range>
      <mat-error>required</mat-error>
    </mat-form-field>
    

    And allow e.g. us use [disabled] to disabled the formControl, and the label move like another mat-input. For this we need add some functions, see (I promise it's the last) this last recent SO

    NOTE: The control is "AS IS" without any warranty and it's allowed: critics it, improve, modify, use or put it as bad example

    0 讨论(0)
  • 2021-01-25 00:12

    In angular material there is an option to specify range https://material.angular.io/components/datepicker/overview#date-range-selection

    <mat-form-field appearance="fill">
      <mat-label>Enter a date range</mat-label>
      <mat-date-range-input [rangePicker]="picker">
        <input matStartDate placeholder="Start date">
        <input matEndDate placeholder="End date">
      </mat-date-range-input>
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-date-range-picker #picker></mat-date-range-picker>
    </mat-form-field>
    

    https://stackblitz.com/angular/pydjpbqmvqq?file=src%2Fapp%2Fdate-range-picker-overview-example.html

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