0
votes

Image:

enter image description here

The code:

TS Controller:

this.formTest = this.formBuilder.group({
    first: ['', Validators.required],
    firsttwo: [''],
    second: this.formBuilder.array([this.formBuilder.group(
        {
            one: ['', Validators.required],
            two: [false],
            three: [false],
            four: []
        })
    ])
});

HTML:

<form [formGroup]="formTest" (ngSubmit)="onLogSubmit()">
    <div class="row">
        <div class="form-group col-6 col-md-2">
            <label for="first">First*</label>
            <div [ngClass]="{'has-error': (formTest.controls.first.errors && formTest.controls.first.dirty), 'has-success': !formTest.controls.first.errors}">
                <input type="number" name="first" min="1" class="form-control" autocomplete="off" placeholder="Nro" formControlName="first" required />
                <!-- Validation -->
                <ul class="help-block">
                    <li *ngIf="formTest.controls.first.errors?.required && formTest.controls.first.dirty">Pakollinen kenttä</li>
                </ul>
            </div>
        </div>
        <div class="form-group col-6 col-md-2">
            <label for="firsttwo">FirstTwo*</label>
            <input type="number" name="firsttwo" min="1" class="form-control" autocomplete="off" placeholder="Nro" formControlName="firsttwo"/>
        </div>
    </div>
    <br>
    <div class="row" formArrayName="second">
        <div class="col-12" *ngFor="let s of formTest.controls.second.controls; let i=index" [formGroup]="s">
            <div class="form-group col-6 col-md-2">
                <label>One</label>
                <input type="number" step="0.1" min="0" class="form-control" formControlName="one">
            </div>                                
            <div class="form-group col-6 col-md-2">
                <label class="form-check checkbox-container">
                    <input type="checkbox" class="form-check-input" formControlName="two">
                    <span class="checkmark"></span>
                    <label class="form-check-label" for="type">Two</label>
                </label>
            </div>
            <div class="form-group col-6 col-md-2">
                <label class="form-check checkbox-container">
                    <input type="checkbox" class="form-check-input" formControlName="three">
                    <span class="checkmark"></span>
                    <label class="form-check-label" for="deco">Three</label>
                </label>
            </div>
            <div class="form-group col-6 col-md-2">
                <label>Four</label>
                <input type="number" step="1" min="0" class="form-control" formControlName="four">
            </div>
        </div>
    </div>
    <br>
</form>

My problem is the following:

  1. Why does a single Validation.required inside FormArray's FormGroup's FormControl paint the entire inner FormGroup with the red bar on the side?
  2. Why is each of the controls of the inner form group on a separate row? The bootstrap normally maintains the correct column distribution correctly, like in the outer form group fields?

EDIT:

  1. Solved, thanks to Eliseo. Had to specifically remove bordering from both the formArrayName-div and [FormGroup]-div, using a simple css-class.

  2. Solved. For some reason the [FormGroup]-div needs its own row-class instead of a column class, so that the child-divs recognize the bootstrap columns.

Corrected version:

<div class="no-validation-color" formArrayName="second">
        <div class="row no-validation-color" *ngFor="let s of formTest.controls.second.controls; let i=index" [formGroup]="s">
.no-validation-color {
    border: 0px;
}
1

1 Answers

1
votes

When a control is invalid, if is inside a FormGroup/FormControl, the FormGroup is invalid too. If the FormGroup/FormArray is inside another FormGroup, this last is invalid too. Angular yet add the class ng-invalid and ng-touched. A silly example Create a form:

  form=new FormGroup({
    name:new FormControl(null,Validators.required)
  })

mannage in a .html

<form [formGroup]="form">
  <input formControlName="name">
</form>

Use this .css

.ng-invalid
{
  border:1px solid red;
}

You see that the input has the border red but also the "form" has a border red. The solucion simply is

input.ng-invalid
{
  border:1px solid red;
}

only the input has now a border red

Well, we want the border only if the input is touched and invalid

input.ng-invalid.ng-touched
{
  border:1px solid red;
}

Another exmple, imagine we has a custom validator over a FormGroup. the constrols inside are valid, but the formGroup is invalid. Some like

  form=new FormGroup({
    name:new FormControl(null,Validators.required),
    group:new FormGroup({
      prop1:new FormControl(),
      prop2:new FormControl()
    },this.customValidator())
  })

  customValidator()
  {
    return (formGroup)=>{
      return !formGroup.value.prop1?{error:'error'}:null
    }
  }

Yes, is a silly example, the group is invalid if prop1 is null or empty

If we make a form like

<form [formGroup]="form">
    <input formControlName="name">
    <div id="group1" formGroupName="group">
        <input formControlName="prop1">
        <input formControlName="prop2">
  </div>
</form>

We can has a .css like

input.ng-invalid.ng-touched
{
  border:1px solid red;
}

/*All the input inside the formGroup with id="group1" if the group1 is invalid*/
#group1.ng-invalid input.ng-touched 
{
  border: 1px solid red!important;
}