0

I have a form that has two date fields and I want to validate that start date is earlier than the end date. Pretty straight forward. I've chosen to implement the form with reactive forms rather than templates. I am using rc5. I've searched a lot and seen examples with directives for the template model (which I've chosen not to pursue at the moment) but the examples that I see for reactive forms do not appear to be working anymore.

You would think this example below would work but it actually doesn't: Cross field validation in Angular2

searchlog.component.html

<form [formGroup]="logsearchForm" >
<p-panel>
  <div class="ui-grid ui-grid-responsive ui-grid-pad ui-fluid">
    <div class="ui-grid-row ui-fluid">
      <div class="ui-grid-col-1">Search Logs</div>
      <div class="ui-grid-col-4 ui-fluid">
        <input type="text" pInputText formControlName="searchString"  placeholder="Enter text you want to search"/>
      </div>
      <div>
        <button pButton type="submit" (ngSubmit) = "searchForLogs(logSearchForm.value, logSearchForm.valid)" label="Search" [disabled]="!logsearchForm.valid"></button>
      </div>
    </div>
    <p-panel>
      <div class="ui-grid-row ui-fluid">
        <div class="ui-grid-col-1">Applications:</div>
        <div class="ui-grid-col-2">
          <p-dropdown [options]="applications" formControlName="selectedApp">
          </p-dropdown>
        </div>

        <div class="ui-grid-col-1">Users:</div>
        <div class="ui-grid-col-2">
          <p-dropdown [options]="users" formControlName="selectedUser"></p-dropdown>
        </div>

      </div>
      <div class="ui-grid-row ui-fluid">
        <div class="ui-grid-col-1">Start Time:</div>
        <div class="ui-grid-col-2">
          <p-calendar formControlName="startDate" dateFormat="mm/dd/yy" timeFormat="HH:mm" timeControlType="select"
                      [horizontalTimeControls]="true"></p-calendar>

        </div>

        <div class="ui-grid-col-1">End Time</div>
        <div class="ui-grid-col-2">
          <p-calendar formControlName="endDate" dateFormat="mm/dd/yy" timeFormat="HH:mm" timeControlType="select"
                      [horizontalTimeControls]="true">>
          </p-calendar>
        </div>

      </div>
    </p-panel>
  </div>
</p-panel>
</form>

searchlog.component.ts

....

  initControls() {
    this.searchStringControl = new FormControl('', Validators.required);
    this.applicationsControl = new FormControl('');
    this.usersControl = new FormControl('');
    this.startDateControl = new FormControl(this.startDate);
    this.endDateControl = new FormControl(this.endDate);
  }

....

  ngOnInit() {
    this.startDate = this.getCurrentTimeAsString();
    this.endDate = this.getTime24HoursAgoAsString();

    this.initControls();

    this.logsearchForm = this.fb.group({
      'searchString': this.searchStringControl,
      'selectedApp': this.applicationsControl,
      'selectedUser': this.usersControl,
      'period': this.fb.group({
        'startDate': this.startDateControl,
        'endDate': this.endDateControl
      })
    })

  }

....

Without even adding a validator to the new FormGroup I get the following error in console.

browser_adapter.js:84ORIGINAL EXCEPTION: Cannot find control with name: 'startDate'

Any idea how to achieve this? You would think this would be a very common problem but all I can find are answers that do not work anymore in Angular 2.

Community
  • 1
  • 1
Greg Hill
  • 2,148
  • 2
  • 23
  • 27
  • I believe this is too late for you, but nevertheless: you need to put in a [formGroup]="period" div surrounding the controls inside that form group. – Spock Oct 10 '16 at 11:13

1 Answers1

0

One way that I found out that works for me (poking around at source code) is:

this.logsearchForm = new FormGroup({
  'searchString': new FormControl('', Validators.required),
  'selectedApp': new FormControl(''),
  'selectedUser': new FormControl(''),
  'startDate': new FormControl(this.startDate, Validators.required),
  'endDate': new FormControl(this.endDate)

}, {}, this.periodValidator);

And the validator below (using moment.js for date manipulation)

periodValidator(formGroup:FormGroup) {
    let stDt = moment(formGroup.value.startDate, "MM/DD/YYYY HH:mm");
    let endDt = moment(formGroup.value.endDate, "MM/DD/YYYY HH:mm");
    if (stDt < endDt) {
      return null;
    }
    else {
      return {'failedDateValidation': true}
    }

  }
Greg Hill
  • 2,148
  • 2
  • 23
  • 27
  • This works for performing validation on the entire form at once, but what if you need a custom validator for a field that depends on other fields? Take, for example, a `confirmPassword` field that can only be valid if it matches what is in the main `password` and when the `password` field is non-blank? Validators for fields get a FormControl, not the entire FormGroup with all of the form values. – Michael Oryl Oct 27 '16 at 13:03