How to add a manual date range input field in an angular picker component

Viewed 40

I am trying to add a manual date range input field in an Angular calendar picker. Specifically, I would like to have two date input fields above the calendar that can allow the user to type in the date range instead of scrolling through months on the calendar.

My current solution was to edit the default calendar header by defining a template and inserting my custom date input pickers. However, as soon as I added this default header component, all functionality was lost.

How can I keep the date range functionality from the default date range Angular component, but also add a manual date picker above the calendar?

Below is my custom header component, but does not have any functionality

Calendar component with custom a header

Below is a working angular calendar component without the custom input range picker

enter image description here

calendar.html

@Component({
  selector: 'calendar',
  templateUrl: '.calendar.component.html',
  styleUrls: ['.calendar.component.scss'],
  providers: [
    {
      provide: DateAdapter,
      useClass: CustomDateAdapter,
      deps: [MAT_DATE_LOCALE, Platform],
    },
  ],
})
export class DateSearchFilterComponent implements OnInit {
  calendarHeader = CalendarHeaderComponent;
  numberOfReschedules: number | null | undefined;
  selectedDateOptions: DateFilterOptions = {
    [DateFilterType.issueDateFilters]: [],
    [DateFilterType.actionDateFilters]: [],
  };

  min: Date = new Date('January 1, 1980');
  today: Date = new Date();
  oneYearFromToday: Date = new Date();

  dateFields: FilterGroup[] = [
    {
      id: DateFilterType.issueDateFilters,
      label: 'CAP DATES',
      fields: [
        {
          name: 'Origination Date',
          dateType: IssueDateType.OriginationDate,
          max: this.today,
        },
        {
          name: 'Discovery Date',
          dateType: IssueDateType.DiscoveryDate,
          max: this.today,
        },
        {
          name: 'Completion Date',
          dateType: IssueDateType.CompletionDate,
          max: this.today,
        },
      ],
    },
  ];

  constructor(
    private activatedRoute: ActivatedRoute,
    private queryParameters: QueryParametersService,
    public featureFlags: FeatureFlagsService,
    private advancedSearch: AdvancedSearchService
  ) {
    this.oneYearFromToday.setFullYear(this.oneYearFromToday.getFullYear() + 1);
    if (this.featureFlags.isFeatureEnabled('action-dates-filter')) {
      this.dateFields.push({
        id: DateFilterType.actionDateFilters,
        label: 'ACTION DATES',
        fields: [
          {
            name: 'Origination Date',
            dateType: ActionDateType.OriginationDate,
            max: this.today,
          },
          {
            name: 'Due Date',
            dateType: ActionDateType.DueDate,
            max: this.oneYearFromToday,
          },

          {
            name: 'Completion Date',
            dateType: ActionDateType.CompletionDate,
            max: this.today,
          },
          {
            name: 'Due Date Extension Count',
            dateType: IssueDateType.CompletionDate,
            max: Number.MAX_SAFE_INTEGER,
          },
        ],
      });
    }
  }

  ngOnInit(): void {
    this.subscribeToServiceOnInit();
  }

  subscribeToServiceOnInit = (): Subscription => {
    return this.activatedRoute.queryParams
      .pipe(
        map((data) => this.queryParameters.deserializeQueryParams(data)),
        untilDestroyed(this)
      )
      .subscribe((res) => {
        let { issueDateFilters, actionDateFilters } = res;
        if (!issueDateFilters) issueDateFilters = [];
        if (!actionDateFilters) actionDateFilters = [];
        this.selectedDateOptions = { issueDateFilters, actionDateFilters };
        this.numberOfReschedules = res.numberOfReschedules;
      });
  };
/** Custom header component for datepicker. */
@Component({
  selector: 'app-calendar-header'
  ],
  template: `
    <div class="calendar">
      <div class="calendar-header">
        <button (click)="previousClicked('month')">˂</button>
        <span>{{ periodLabel }}</span>
        <button (click)="nextClicked('month')">˃</button>
      </div>

      <div class="date-inputs">
        <div>
          <span>From</span>
          <input type="date" />
        </div>
        <span class="date-inputs--dash">—</span>
        <div>
          <span>To</span>
          <input type="date" />
        </div>
      </div>
    </div>
  `,
  // changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CalendarHeaderComponent<D> implements OnDestroy {
  private destroyed = new Subject<void>();

  constructor(
    private calendar: MatCalendar<D>,
    private dateAdapter: DateAdapter<D>,
    @Inject(MAT_DATE_FORMATS) private dateFormats: MatDateFormats,
    cdr: ChangeDetectorRef
  ) {
    calendar.stateChanges
      .pipe(takeUntil(this.destroyed))
      .subscribe(() => cdr.markForCheck());
  }

  ngOnDestroy() {
    this.destroyed.next();
    this.destroyed.complete();
  }

  get periodLabel() {
    return this.dateAdapter
      .format(this.calendar.activeDate, this.dateFormats.display.monthYearLabel)
      .toLocaleUpperCase();
  }

  previousClicked(mode: 'month' | 'year') {
    this.calendar.activeDate =
      mode === 'month'
        ? this.dateAdapter.addCalendarMonths(this.calendar.activeDate, -1)
        : this.dateAdapter.addCalendarYears(this.calendar.activeDate, -1);
  }

  nextClicked(mode: 'month' | 'year') {
    this.calendar.activeDate =
      mode === 'month'
        ? this.dateAdapter.addCalendarMonths(this.calendar.activeDate, 1)
        : this.dateAdapter.addCalendarYears(this.calendar.activeDate, 1);
  }
}
 <mat-form-field
          attr.data-cy="{{ input.label }} {{ field.name }}"
          *ngIf="field.name !== 'Due Date Extension Count'"
          appearance="outline"
          class="date-input body-regular"
        >
          <mat-label class="select-label body-regular">
            {{
              !(determineFilterIndex(input.id, field.dateType) !== -1)
                ? 'Select...'
                : ''
            }}
          </mat-label>
          <!-- Input Fields -->
          <mat-date-range-input
            class="date-range-input"
            [rangePicker]="picker"
            [max]="field.max"
            [min]="min"
            #dateRangePicker
          >
            <!-- Start Date -->
            <input
              #start
              matStartDate
              (blur)="
                handleBlur(
                  dateRangePicker.value?.start,
                  dateRangePicker.value?.end,
                  field.dateType,
                  input.id
                )
              "
              (dateChange)="
                handleDateSelection(
                  dateRangePicker.value?.start,
                  dateRangePicker.value?.end,
                  field.dateType,
                  input.id
                )
              "
              placeholder="Start date"
              class="body-small"
              [value]="
                determineCurrentFilterValue(input.id, field.dateType)?.startDate
              "
            />
            <!-- End Date -->
            <input
              #end
              (blur)="
                handleBlur(
                  dateRangePicker.value?.start,
                  dateRangePicker.value?.end,
                  field.dateType,
                  input.id
                )
              "
              (dateChange)="
                handleDateSelection(
                  dateRangePicker.value?.start,
                  dateRangePicker.value?.end,
                  field.dateType,
                  input.id
                )
              "
              matEndDate
              placeholder="End date"
              class="body-small date-end"
              [value]="
                determineCurrentFilterValue(input.id, field.dateType)?.endDate
              "
            />
          </mat-date-range-input>

          <!-- Calendar Icon Toggle Button -->
          <mat-datepicker-toggle
            attr.data-cy="{{
              input.label.trim().toLowerCase().replace(' ', '-')
            }}-{{ field.name.trim().toLowerCase().replace(' ', '-') }}"
            class="calendar-suffix"
            matSuffix
            [for]="picker"
            ><mat-icon
              class="calendar-icon"
              matSuffix
              matDatepickerToggleIcon
              svgIcon="calendar"
            ></mat-icon
          ></mat-datepicker-toggle>

          <!-- Custom Header -->
          <mat-datepicker
            #picker
            [calendarHeaderComponent]="calendarHeader"
          ></mat-datepicker>

          <!-- Clear and Apply buttons -->
          <mat-date-range-picker #picker>
            <mat-date-range-picker-actions>
              <button
                mat-button
                matDateRangePickerCancel
                class="clear-button"
                (click)="clearFilter(input.id, field.dateType)"
              >
                Clear
              </button>
              <button
                mat-raised-button
                color="accent"
                class="apply-button"
                matDateRangePickerApply
              >
                Apply
              </button>
            </mat-date-range-picker-actions>
          </mat-date-range-picker>
        </mat-form-field>

0 Answers
Related