2

Reactive Form having dynamic patten validation is always invalid on first load. Even after I edit it still invalid.

This is happening only when I am adding dynamic pattern matching validation.

Here is my use case :

  • On UI there is table and edit button in last row
  • Initially No formcontrols are visible
  • User Clicks on edit button then form control gets appear.

Refer this stackblitz

Below is code

<form [formGroup]="data_form">
    <table class="table table-border">
        <thead>

            <th>
                name
            </th>
            <th>
                age
            </th>
            <th><button class="btn btn-primary ">Save</button></th>
        </thead>
        <tbody>
            <ng-container *ngFor='let item of data;let j = index'>
                <tr>
                    <ng-container *ngFor="let td of keys;let i = index">
                        <ng-container>

                            <td  *ngIf="td !=='isEditable'">
                                {{item[td]}}
                                <input   [formControlName]="getControlName(j,i)" *ngIf="item.isEditable" type="text" name="" id="">
          </td>

                        </ng-container>
                    </ng-container>

                    <td>
                        <button (click)="item.isEditable = true"> Edit</button>
                    </td>
                </tr>
            </ng-container>
        </tbody>
    </table>

</form>

ts code :

import { Component } from "@angular/core";
import { FormControl, FormGroup, Validators } from "@angular/forms";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  name = "Angular";
  data_form = new FormGroup({});
  public data;
  keys;

  ngOnInit() {
    this.data = [
      {
        name: "Sachin",
        age: 27,

        isEditable: false
      },
      {
        name: "Gopal",
        age: 27,

        isEditable: false
      },
      {
        name: "Pankaj",
        age: 24,

        isEditable: false
      }
    ];
    this.keys = Object.keys(this.data[0]);
    this.data.forEach((element, j) => {
      this.keys.forEach((k, i) => {
        this.data_form.addControl(
          "name_" + j + "_" + i,
          new FormControl(element[k], [Validators.required, Validators.pattern(/^[.\d]+$/)])
        );
      });
    });
  }

  log() {
    console.log(this.data);
  }

  getControlName(j, i) {
    return "name_" + j + "_" + i;
  }
}

Thanks in Advance.

EDIT:

Various Patterns that I have used :

  • Validators.pattern("^[a-zA-Z0-9 _/]+$")
  • Validators.pattern(/^[.\d]+$/)
  • Validators.pattern(/^(yes|no)$/i)
  • Validators.pattern(/^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/)

1 Answer 1

1

The problem is actually because the pattern is being used for all the controls. I have refactored your code using FormArray and it seems your pattern work fine

Below is my approach TS File

  constructor(private fb: FormBuilder) {}
  patterns = [
    /^[.\d]+$/,
    /^(yes|no)$/i,
    /^[a-zA-Z0-9 _/]+$/,
    /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/
  ];
  data = [
    {
      name: "Sachin",
      age: 27,
      isEditable: false
    },
    {
      name: "Gopal",
      age: 27,

      isEditable: false
    },
    {
      name: "Pankaj",
      age: 24,

      isEditable: false
    }
  ];
  keys = [...new Set(this.data.map(item => Object.keys(item)).flat())];
  keyPattern = this.keys.map(item => ({
    key: item,
    pattern: this.patterns.find(pattern =>
      this.data.every(i => pattern.test(i[item]))
    )
  }));
  data_form = this.fb.group({
    persons: this.fb.array(
      this.data.map(item =>
        this.fb.group(
          this.keyPattern.reduce(
            (prev, { key, pattern }) => ({
              ...prev,
              [key]: [
                item[key],
                [Validators.required, Validators.pattern(pattern)]
              ]
            }),
            {}
          )
        )
      )
    )
  });
  get persons(): FormArray {
    return this.data_form.get("persons") as FormArray;
  }

  toggleEdit(j) {
    const currentEditStatus = this.persons.controls[j].get("isEditable").value;
    this.persons.controls[j].get("isEditable").setValue(!currentEditStatus);
  }

HTML

<form [formGroup]="data_form">
    <table class="table table-border">
        <thead>
      <tr>
        <th> name </th>
            <th>age </th>
            <th><button class="btn btn-primary ">Save</button></th>
      </tr>
        </thead>
        <tbody formArrayName='persons'>
            <ng-container *ngFor='let item of persons.controls;let j = index'>
                <tr [formGroupName]='j'>
                    <ng-container *ngIf="!item.value.isEditable; else editable">
                        <td>{{ item.value.name }}</td>
                        <td>{{ item.value.age }}</td>
                    </ng-container>
                    <ng-template #editable>
                        <td><input formControlName='name'></td>
                        <td><input formControlName='age'></td>
                    </ng-template>
                    <td>
                        <button (click)="toggleEdit(j)">
              {{ !item.value.isEditable ? "Edit": "Cancel"}}
            </button>
                    </td>
                </tr>
            </ng-container>
        </tbody>
    </table>

</form>

See below fork Demo

Sign up to request clarification or add additional context in comments.

14 Comments

Validators.pattern("^[a-zA-Z0-9 _/]+$") I have this one also ..So here what I need to escape ?
okay let me update various patterns that I have used in question
The only way I can think of is a reactive programming approach to avoid issues such as expressions changedAfterItWasChecked Error, will update my answer
You can use the above as a starter
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.