5

I'm building a Wizard in Angular2 - Redux. I'm using Reactive Forms to handle & submit data for every step inside. I need to trigger form validation programmatically, because the declaration of my call-to-action button, in order to go to the next step, is in a separated component from the stepComponent. See wireframe below

Components's wireframe

enter image description here

Current Behavior

  1. Only when a change has ocurred on a form's control, its own validation runs. And it's touched & valid property is updated accordingly.

  2. As I am in a Redux environment, I dispatch an action to get the current-step form data in order to be applied to the payload. When that's is finished, I trigger another action to save data.

  3. Actually, I know when the form is valid or invalid by using:

     submitForm(form: FormGroup):void{
        if(form.valid){
          this.actionsStep.saveStep(form.value);
        }else{
          console.log('Form invalid ')
        }
      }
    
  4. As my forms uses controls's properties to render a custom message when a error has happened, I want to re-run validation by submit the form or by using another function to be able to use the control's properties again to notify where an error has occurred.

StepComponent.ts : Form declaration

this.stepForm = this.formBuilder.group({
  name: ['', Validators.required],
  email: ['', Validators.required]
});

step-component.html : Form HTML

<form id="ngForm" [formGroup]="stepForm" (ngSubmit)="submitForm(stepForm.value)" class="form-horizontal form-box-content">
    <div class="form-group row" [ngClass]="{'has-danger' :name.invalid && name.touched}">
      <label class="col-md-2 col-form-label">Name:</label>
      <div class="col-md-10">
        <input 
        name="titulo" class="form-control required" 
               formControlName="name" placeholder="" type="text"  [ngClass]="{'form-control-danger' :name.invalid && name.touched}" >
        <small class="form-control-feedback text-danger" *ngIf="name.invalid && name.touched && name.hasError('required')">
          The name is required
        </small>
      </div>
  </div>

Attemps

I tried to use

  1. Update Validity:

    this.stepForm.updateValueAndValidity();

  2. Update Validity providing params:

    this.stepForm.updateValueAndValidity({ onlySelf: false, emitEvent: true });

  3. Mark each control as touched (To trigger event as I've typed something)

    for (var i in this.stepForm.controls) { this.stepForm.controls[i].markAsTouched(); }

  4. The solutions which requires submit function to be called from the HTML will not work for me because the button and the form are in separated components.

5. Is there any way to trigger or update validation programmatically or at least to submit a form properly in a function?

Previous Research

I found many help links to achieve this, however,those solutions work only when the button is declared in the same component. And also, when button is inside the form tag:

Leo
  • 1,051
  • 2
  • 13
  • 33
  • 1
    What is the problem you are facing with the current approach? – Harry Ninh Jul 05 '17 at 05:12
  • Can you construct a minimal working example? – yurzui Jul 05 '17 at 06:12
  • @HarryNinh , the problem is that I can not trigger the form validation from js . I wonder if there is any way to do this. I was thinking that by submitting the form would result that inner validation runs; however, I do not find a way to submit from js, either. – Leo Jul 05 '17 at 07:59
  • Ok so short version: 1) the form is automatically validated every time a field value is updated; 2) you can retrieve form value and do HTTP POST request to submit the form – Harry Ninh Jul 05 '17 at 10:02
  • @HarryNinh thanks about that. So, actually there's no way to validate the form manually, without the need to updated or touch the controls, is it? – Leo Jul 05 '17 at 14:51
  • @leonardovidal I don't fully get your intention here, why do you need to re-validate an untouched form? Say you have 2 variables `a = 1` and `b = 1`, no matter how many time you do `a + b`, the result is still is `2`. A form that has the same value will always be either valid or invalid no matter how many times you validate it. – Harry Ninh Jul 06 '17 at 00:25
  • I can understand your point. My goal is to show what fields are not filled correctly or empty when the user click the next button. This is a common user's behavior for any form on submit. Currently, in html, the error messages are connected with the property valid & touched. And only when they are touched and then lost the focus with incorrect information, like empty , the control updates its properties in the component and the view properly. Is there a way to mark all controls as touched and run validation for each of them in a function? – Leo Jul 06 '17 at 03:04

2 Answers2

0

I basically had the same setup, and got around it by doing the equivalent of

(this.stepForm as any).submitted = true
Brian Davis
  • 745
  • 1
  • 11
  • 14
0

In case someone else is still trying to do this. I did this by using ViewChild to grab references to the referenced components and stepper. Then control the next button click and do not have matStepperNext on the button.

<button mat-button (click)="onStepOneNextClick()">Next</button>

@ViewChild(MatStepper) stepper: MatStepper;
@ViewChild(StepOneComponent, { static: true }) stepOneComponent: StepOneComponent;

onStepOneNextClick() {
  if (this.stepOneComponent.form.invalid) {
    this.stepOneComponent.form.markAllAsTouched();
  }
  else {
    this.stepper.next();
  }
}

Gabe
  • 122
  • 5