Home > Software design >  Enable/Disable button based on input
Enable/Disable button based on input

Time:05-20

I have an input field for selecting date. I want to apply simple validation that if this field is empty then the submit button should be disabled and enabled when it's filled and it shoud be in sync.

The date field is having some issue, when I checked through ng-valid it is supposed to give false when nothing is entered into the date field but it's giving true right from the word go.

I created a simple example using StackBlitz having a single input of date, now I need to disable it when input field is empty and activate it when input is filled.

https://stackblitz.com/edit/ngx-daterangepicker-material-for-angular8-5ikovy?file=src/app/app.component.html

CodePudding user response:

It is due to the poor implementation on the date picker part. By default, they set value of the control to {start: null, end: null}. https://stackblitz.com/edit/ngx-daterangepicker-material-for-angular8-fa73zq?file=src/app/app.component.html

The default required validator checks if the controlValue == null and the object that is set to the control by library is not null-ish. In case if you need to use this library, you need to write your custom validator that would check if both start and end are null and if so it should return an error.

You check how to do it here: https://angular.io/guide/form-validation#adding-custom-validators-to-template-driven-forms

CodePudding user response:

By default, when your input date is empty its value is { "start": null, "end": null } . So the "required" validator does not invalidate the value, because this is a valid object.

A simple way to fix:

<button
  [disabled]="!(date.value.start && date.value.end)"
>...</button>

CodePudding user response:

As others have mentioned, this is due to the value being { start: null, end: null }. You could fix this by creating a custom validator - the benefit of doing it this way is your valid state of your form will be correct.

You could define a validator as a directive as follows (there may be an interface already existing in your date picker package, so may not need that part):

interface DateRange {
  start: Moment | null;
  end: Moment | null;
}

@Directive({
  selector: '[appDateRange]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: DateRangeValidatorDirective,
      multi: true,
    },
  ],
})
export class DateRangeValidatorDirective implements Validator {
  validate(control: AbstractControl): ValidationErrors | null {
    return this.dateRangeValidator(control);
  }

  dateRangeValidator: ValidatorFn = (
    control: AbstractControl
  ): ValidationErrors | null => {
    if (!control.value) return null;
    const dateRange = control.value as DateRange;
    console.log('VALIDATE', dateRange);
    return dateRange.start && dateRange.end ? null : { dateRange: true };
  };
}

Make sure to define this in your module also:

@NgModule({
  declarations: [
    ...
    DateRangeValidatorDirective
  ]
  ...
})

You can then use this, exactly like your required validator on the input using the directive selector (appDateRange):

<input ... appDateRange>

So could on your button have:

<button ... [disabled]="date.errors?.required && date.errors?.dateRange"> ...

If you want to find out more about this, there is a very good example here https://angular.io/guide/form-validation, forbiddenNameValidator on the page.

  • Related