Дублирование форм с помощью логики

#javascript #angular #typescript #angular8

#javascript #угловой #typescript #angular8

Вопрос:

Я создал поле динамической формы, которое я добавляю и удаляю с помощью функции обратного вызова на кнопках DelBtn() , чтобы удалить элемент и AddBtn() добавить элемент

Каждое из полей этой формы имеет value ввод

У меня также есть totalval поле. Я ожидаю, что сумма значений во всех value полях не будет превышать totalval . Если это так, мы выводим сообщение об ошибке a, и если значение равно, мы выводим поле reason формы.

Пример:

Если у меня есть totalValue = 100 . Теперь допустим, у меня есть мое первое поле формы value = 90 .

Затем я дублирую форму и в следующем наборе полей value = 10 reason поле должно появиться, потому 90 10 = 100 что. По мере totalValue достижения должно появиться поле reason формы, а кнопка добавления должна быть отключена.

Если при второй попытке пользователь попытается ввести значение больше 10, должно появиться сообщение об ошибке.

Ниже приведен мой текущий код

В моем TS-файле у меня есть

   ischecks: boolean = true;
  formsArray = [""];
  count: number = 0;
  totalval: number = 100;

  ngOnInit(): void {}
  constructor() {}

  clickCount(): void {
    this.count  ;
  }

  DelBtn = delIndex => this.formsArray.splice(delIndex, 1);
  AddBtn = () => this.formsArray.push("");
  

HTML

 <h2> Form</h2>

<pre style="font-weight: bolder;font-family:verdana;margin-left: 35px;">Total Value:{{totalval}}       </pre>
<div *ngFor="let i of formsArray; let a = index">

    <div>
        <form>
            <table>
                <div>
                    <label for="fname">Value:</label><br>
                    <input type="text" id="fname" name="fname" ><br>
                    <tr>
                        <td>
                            <button type="button" class="btn btn-outline-success"
        style="border-radius:40px;margin-left: 50px" (click)="DelBtn(a)" ><span class="fa fa-plus"></span>Delete</button>
                        </td>
                    </tr>
                    <tr>
                </div>
            </table>
        </form>
    </div>
</div>

<div *ngIf=ischecks style="margin-left:35%">
    <label for="fname">Reason:</label><br>
    <input type="text" id="fname" name="fname" ><br>
</div>
    <br>
    <button type="button" class="btn btn-outline-success"
            style="border-radius:40px;margin-left: 50px;margin-bottom: 30%;" (click)="AddBtn()"  ><span class="fa fa-plus"></span>Add</button>
  

https://stackblitz.com/edit/angular-ivy-3pbdwv?file=src/app/app.component.html

Примечание: Если вы не понимаете вопрос, не стесняйтесь задавать мне в комментариях, adn Я работаю в angular (typescript)

Ответ №1:

Этого будет трудно достичь с помощью basic Javascript . Приведенный ниже подход использует ReactiveForm подход

Мы выполняем следующие шаги

  • Добавьте ReactiveFormsModule в imports массив модуля
 @NgModule({
  imports:[ ReactiveFormsModule, ... ],
  
  • Внедрить FormBuilder класс
 constructor(private fb: FormBuilder) {}
  
  • Определите форму
 myForm = this.fb.group({
  totalVal: [100],
  formsArray: this.fb.array([this.fb.control("", { validators: [Validators.required] })]),
  reason: ["", [Validators.required]]
}, { validators: [sumMatches] });
  

Мы добавили средство проверки cusom sumMatches . Мы будем использовать это, чтобы проверить, была ли сопоставлена сумма общего значения

 function sumMatches(control): ValidationErrors | undefined {
  const totalVal = Number(control.get("totalVal").value);
  const formsArrayTotal = control
    .get("formsArray")
    .value.reduce((a, b) => Number(a)   Number(b), 0);
  if (formsArrayTotal !== totalVal) {
    return {
      sumMismatch: true
    };
  }
  return;
}
  
  • Далее мы определяем вспомогательные getter функции для извлечения свойств из formGroup
   get sumMismatch(): boolean {
    return this.myForm.hasError('sumMismatch')
  }
  get arrayFullyFilled() {
    return !this.formsArray.controls.some(item => item.errors)
  }
  get formsArray() {
    return this.myForm.get("formsArray") as FormArray;
  }
  get totalVal() {
    return this.myForm.get("totalVal") as FormControl;
  }
  
  • Нам также необходимо изменить функции для добавления и удаления элементов из FormArray
   DelBtn = delIndex => this.formsArray.controls.splice(delIndex, 1);
  AddBtn = () => this.formsArray.push(this.fb.control(""));
  
  • Наконец, мы можем реализовать formGroup в html
 <h2> Form</h2>

<span class='totalVal'>Total Value:{{ totalVal.value }}</span>

<form [formGroup]='myForm'>
    <ng-container formArrayName='formsArray'>
        <table *ngFor="let item of formsArray.controls; let i = index">
            <tr>
                <td>
                    <div>
                        <label [attr.for]="'fname'   i">Value:</label><br>
                        <input type="number" [formControlName]="i" type="text" [id]="'fname'   i" name="fname" ><br>
                </div>
                </td>
                <td>
                    <button type="button" class="btn btn-outline-success"
        s (click)="DelBtn(i)" ><span class="fa fa-plus"></span>Delete</button></td>
            <tr>

        </table>
    </ng-container>
    <div *ngIf='!sumMismatch amp;amp; arrayFullyFilled'>
        <label for="fname">Reason:</label><br>
        <input type="text" id="fname" name="fname" ><br>
</div>
        <br>
        <button type="button" class="btn btn-outline-success"
       (click)="AddBtn()"  ><span class="fa fa-plus"></span>Add</button>
        <br>
  <span class="error" *ngIf="sumMismatch amp;amp; myForm.touched">Total Value Mismatch</span>
</form>
  

Я извлек css в собственный файл

 .totalVal {
  font-weight: bolder;
  font-family: verdana;
}
.btn-outline-success {
  border-radius: 40px;
  margin-left: 50px;
}
.error {
  color: red;
}

  

Посмотрите эту демонстрацию

Редактировать 1 — Как работает валидатор?

Чтобы понять это, мы рассмотрим, как мы создаем нашу группу форм. Мы определили структуру, которая создает значение в форме

   {
    totalVal: 100,
    formsArray: [''],
    reason: ''
  }
  

Определяя нашу группу форм как this.fb.group({ ... }, {validators: [ sumMatches ] } группу форм с указанным выше значением, она будет передана функции суммирования

В у sumMatches нас будет что-то вроде a formGroup со значением

   {
    totalVal: 100,
    formsArray: ['50', '20', '10'],
    reason: ''
  }
  

В приведенном выше примере мы просто извлекаем 100 из того formGroup control.get('totalVal').value же to formArray . Поскольку formArray значение будет массивом, мы можем использовать reduce функцию для суммирования этого.. Мы, наконец, сравниваем это и возвращаем null, если они совпадают, и an Object , если они не совпадают.

При вышеуказанном подходе угловые реактивные формы обновят значение статуса формы valid на основе того, что предоставлено пользователем. Следовательно, мы можем использовать этот valid статус для обновления UI

arrayFullyFilled()

 get arrayFullyFilled() { 
  return !this.formsArray.controls.some(item => item.errors) 
}
  

Приведенный выше код пытается определить, заполнил ли пользователь ВСЕ входные данные в массиве. В нашем массиве мы получаем все элементы управления, проверяем, есть ли в некоторых из них ошибки, и если в каком-либо из них есть ошибка, возвращает false, в противном случае возвращает true. Это стало возможным, учитывая, что в моем formGroup я сделал formControls as required с помощью Validators.required проверки

Комментарии:

1. Привет, спасибо за ответ. не могли бы вы подробно объяснить код?

2. В какой части вы хотели бы получить разъяснения?

3. Можете ли вы объяснить мне раздел, требующий проверки. Я понимаю функциональность, но можете ли вы объяснить, как вы зациклили formbuilder внутри себя?

4. get arrayFullyFilled() { return !this.formsArray.controls.some(item => item.errors) } Я тоже не совсем понимаю эту строку?