Value issues when wrapping DateRange in custom component

1 Answer 118 Views
DateInput DateRange
Joe
Top achievements
Rank 1
Iron
Iron
Joe asked on 02 Feb 2023, 05:31 PM

Hey everyone!

I'm currently trying to wrap a DateRange component inside of a custom component in my application so that I can add boilerplate configuration in a single place. Everything was going well until I tried to set the value from a parent component. When I attempt to set the value writeValue inside the component is called properly and sets the value HOWEVER the value is then immediately overwritten and a "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'Thu Feb 02 2023 10:56:57 GMT-0600 (Central Standard Time)'. Current value: 'null'" error is written to the console. If I look at the stacktrace it is pointing to the start date input in the component template.

Is there something in the component lifecycle that could be causing this issue? I have verified that nothing else attempts to set the value of the component.

Thanks in advance for any help or insight.

component.html

<kendo-daterange>
  <kendo-floatinglabel text="{{label}}">
    <kendo-dateinput kendoDateRangeStartInput [min]="selectRange.startDate" [max]="selectRange.endDate" [(value)]="startDate" fillMode="outline"></kendo-dateinput>
  </kendo-floatinglabel>
  <kendo-floatinglabel text="">
    <kendo-dateinput kendoDateRangeEndInput [min]="selectRange.startDate" [max]="selectRange.endDate" [(value)]="endDate" fillMode="outline"></kendo-dateinput>
  </kendo-floatinglabel>
  <kendo-daterange-popup (close)="onClose()"></kendo-daterange-popup>
</kendo-daterange>

component.ts


import {Component, forwardRef, Input, OnInit, ViewEncapsulation} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { TICKET_DATE_FORMAT, DATE_CONSTS } from 'core/constants';
import { DateRange } from 'core/models/date-range';

@Component({
    selector: 'lm-date-range',
    templateUrl: './lm-date-range.component.html',
    styleUrls: ['./lm-date-range.component.scss'],
    providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          multi:true,
          useExisting: LMDateRangeComponent
        }
      ]
  })
  
export class LMDateRangeComponent implements ControlValueAccessor, OnInit {

    protected selectRange: DateRange = {startDate: DATE_CONSTS.MIN_DATE, endDate: DATE_CONSTS.MAX_DATE};
    protected dateFormat = TICKET_DATE_FORMAT;

    onChange = (value: DateRange) => {};
    onTouched = () => {};
    touched = false;
    disabled = false;

    @Input() label: string;
    startDate: Date = null;
    endDate: Date = null;
    value: DateRange = null;

    constructor() {
        var x = 5;
    }

    ngOnInit(): void {
        var x = 5;
    }

    writeValue(selected: DateRange) {
        this.onChange(selected);
        if (selected) {
            this.value = {
                startDate: typeof selected.startDate === 'string' ? new Date(selected.startDate) : selected.startDate,
                endDate: typeof selected.endDate === 'string' ? new Date(selected.endDate) : selected.endDate,
            };    
            this.startDate = this.value.startDate;
            this.endDate = this.value.endDate;
        }
        else {
            this.value = null;
            this.startDate = null;
            this.endDate = null;
        }
    }

    registerOnChange(onChange: any) {
        this.onChange = onChange;
    }

    registerOnTouched(onTouched: any) {
        this.onTouched = onTouched;
    }

    markAsTouched() {
        if (!this.touched) {
            this.onTouched();
            this.touched = true;
        }
    }

    setDisabledState(disabled: boolean) {
        this.disabled = disabled;
    }

    onClose() {
        this.markAsTouched();
        this.value = { startDate: this.startDate, endDate: this.endDate };
        this.onChange(this.value);
    }
}

parentcomponent.html (just the component definition)

<lm-date-range formControlName="issueDateRange" label="Issue Date/Timeframe" class="range-input"></lm-date-range>

parentcomponent.ts

(the ticket variable is passed as an input to this component)

ngOnInit() { if (this.ticket) { this.f.issueDateRange.setValue({startDate: this.ticket.startDate, endDate: this.ticket.endDate}); } else { this.f.issueDateRange.setValue({startDate: newDate(), endDate: newDate()}) } }

1 Answer, 1 is accepted

Sort by
0
Accepted
Joe
Top achievements
Rank 1
Iron
Iron
answered on 06 Feb 2023, 01:55 PM
Turns out there was another issue in the component hierarchy that was causing this issue. 
Tags
DateInput DateRange
Asked by
Joe
Top achievements
Rank 1
Iron
Iron
Answers by
Joe
Top achievements
Rank 1
Iron
Iron
Share this question
or