Search code examples
htmlangularformsvalidationhidden-field

Angular6 | Disable form validation for hidden fields


Background

I have a form where I give the user the option to specify either a quick time-frame or a detailed one (with a specific start/end time) - i.e. the user has the option to fill only one out of the two

The type of option that they wish to choose can be toggled with the click of a button. These buttons just toggle the hidden parameter on the specified divs

Issue

My problem here is that both of these fields (all 3 technically as start/end time are 2 separate form group divs under one generalized div) are required only if they are not hidden - I am not sure how this can be achieved with Angular 4/5/6 (using 6 here)

My invalid form trigger always goes off as the hidden field is also required

My Form

<div class="card-block">
  <form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
    <div class="form-group">
      <label for="transactionType"> Request Type </label>
      <select 
      class="form-control" 
      [(ngModel)]=data.transactionType 
      name ="transactionType" 
      #transactionType="ngModel"
      required>
        <option value="something1Count">Something1</option>
        <option value="something2Count">Something2</option>
      </select> 
      <div *ngIf="transactionType.errors?.required && transactionType.touched" class="alert alert-danger">
        Please select a transaction type
      </div>
    </div>
    <br>
    <div class="form-group">
     <label>Timeframe Type</label> 
     <br>
        <button type="button" class="btn btn-light" (click)="quickTimeframe = false; detailedTimeframe = true;" ng-selected="!quickTimeFrame"> Quick </button>
        <button type="button" class="btn btn-light" (click)="detailedTimeframe = false; quickTimeframe = true;" ng-selected="!detailedTimeframe"> Detailed </button>
    </div>
    <div class="form-group" [hidden]="quickTimeframe">
      <label for="timeframe">Timeframe</label>
      <select 
      class="form-control" 
      [(ngModel)]=data.timeframe 
      name ="timeframe"
      #timeframe="ngModel"
      required>
        <option value="15">15 Minutes</option>
        <option value="30">30 Minutes</option>
        <option value="45">45 Minutes</option>
        <option value="60">60 Minutes</option>
      </select>
      <div *ngIf=" !quickTimeframe && timeframe.errors?.required && timeframe.touched" class="alert alert-danger">
        Please select a timeframe
      </div>
    </div>

      <div class="detailed" [hidden]="detailedTimeframe">
          <div class="form-group">
              <label for="startTime">Start of Time Range</label>
                  <input 
                  type="datetime-local"
                  class="form-control"
                  [(ngModel)]="data.startTime"
                  #startTime="ngModel"
                  name="startTime"
                  required
                  >
              <div *ngIf="!detailedTimeframe && startTime.errors?.required && startTime.touched" class="alert alert-danger">
                Please select a start-time
              </div>
            </div>

            <div class="form-group">
                <label for="endTime">End of Time Range</label>
                <input
                type="datetime-local"
                class="form-control"
                [(ngModel)]="data.endTime"
                #endTime="ngModel"
                name="endTime"
                required
                >
              <div *ngIf="!detailedTimeframe && endTime.errors?.required && endTime.touched" class="alert alert-danger">
                Please select an end-time
              </div>
            </div>
      </div>
    <input type="submit" class="btn btn-primary btn-block" value="Submit">
  </form>
  </div>
</div>

TS File

import { Component, OnInit } from '@angular/core';
import { Inputs } from '../../models/Inputs';
import { Router } from '@angular/router';
import {FlashMessagesService} from 'angular2-flash-messages';

@Component({
  selector: 'app-main-form',
  templateUrl: './main-form.component.html',
  styleUrls: ['./main-form.component.css']
})
export class MainFormComponent implements OnInit {

  data:Inputs = {
    transactionType:'',
    timeframe:null,
    startTime:'',
    endTime:''
  };

  quickTimeframe:boolean=true;
  detailedTimeframe:boolean=true;
  buttonResult:any;

  constructor(public router:Router, public flashMessagesService:FlashMessagesService) { 

  }

  ngOnInit() {

  }

  onSubmit({value, valid}:{value:Inputs, valid:boolean}){

    console.log("Quick Time Flag: " +this.quickTimeframe);
    console.log("Detailed Time Flag: " +this.detailedTimeframe);

    if (valid && !this.quickTimeframe){
      console.log("Form is valid");
      //Stuff should happen
      console.log(value);
    } else if (valid && !this.detailedTimeframe) {
      console.log(this.data.startTime);
      //Other stuff should happen
    } 

    else {
      console.log("Form is not valid");
      this.flashMessagesService.show('Choose Valid Parameters', {cssClass:'alert-danger', timeout: 4000});
    }

  }

  radioClick() {
    console.log(this.buttonResult);
  }

}

Report Inputs Interface (for completion's sake)

 export interface Inputs {

    transactionType?:string;
    timeframe?:number;
    startTime?:string;
    endTime?:string;

}

Solution

  • *ngIf did the trick

    Using ngIf instead of hidden ensure that the elements do not exist within the form in my scenario