Сравните значения двух полей ввода, чтобы проверить форму в Angular 7 через шаблон.

Я нахожусь в первые недели перехода на Angular 7, я делаю базовые формы в своем проекте, используя базовые проверки на основе шаблонов, но мне нужно проверить форму сейчас, основываясь на том, что значение одного поля должно быть выше, чем значение Другой

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

if (issueThresholdForm.value.lowScore > issueThresholdForm.value.highScore) {
  // Show user error
  // This is the messing part, I guess
}

Вот шаблон, который я использую

<div *ngIf="_issueCategory">
  <form (submit)="submitIssueThreshold(issueThresholdForm)" #issueThresholdForm="ngForm">
    <mat-form-field class="half-width" floatLabel="always">
      <mat-label [translate]="'issueThreshold.modals.highScore'"></mat-label>
      <input name="highScore" type="number" matInput placeholder="0" [(ngModel)]="_issueCategory.highScore"
        required #highScore="ngModel">
    </mat-form-field>
    <mat-form-field class="half-width" floatLabel="always">
      <mat-label [translate]="'issueThreshold.modals.lowScore'"></mat-label>
      <input name="lowScore" type="number" matInput placeholder="0" [(ngModel)]="_issueCategory.lowScore"
        required #lowScore="ngModel">
    </mat-form-field>
    <mat-form-field class="full-width" floatLabel="always">
      <mat-label [translate]="'issueThreshold.modals.description'"></mat-label>
      <textarea name="description" matInput [(ngModel)]="_issueCategory.thresholdDescription">
            </textarea>
    </mat-form-field>
    <div class="modal-footer">
      <button type="button" class="btn btn-secondary" data-dismiss="modal" [translate]="'modal-confirm.cancel'"></button>
      <button type="submit" class="btn btn-primary primary" [disabled]="issueThresholdForm.invalid || issueThresholdForm.pristine" [translate]="'modal-confirm.submit'"></button>
    </div>
  </form>
</div>

person user1712638    schedule 29.09.2019    source источник
comment
добавьте URL stackBlitz, будет легко получить быстрый ответ   -  person Indrakumara    schedule 29.09.2019
comment
не связано, но я бы предложил перейти на реактивные формы, которые легко обрабатывать в таких случаях с помощью специального валидатора. Конечно, вы можете сделать собственный валидатор и в формах, управляемых шаблонами.   -  person AJT82    schedule 29.09.2019
comment
реактивные формы также помогут в написании лучших модульных тестов.   -  person Nithin Kumar Biliya    schedule 29.09.2019


Ответы (3)


ИЗМЕНИТЬ:

Отредактировано тем же решением реактивным способом. Поэтому создайте группу форм и добавьте собственный валидатор, прикрепленный к группе форм:

_issueCategory = { lowScore: 1, highScore: 2 };

issueThresholdForm: FormGroup;

constructor(private fb: FormBuilder) {
  this.issueThresholdForm = this.fb.group({
    highScore: [this._issueCategory.highScore, [Validators.required]],
    lowScore: [this._issueCategory.lowScore, [Validators.required]]
  }, { validators: validateScore })
}

Функция валидатора:

export function validateScore(
  control: AbstractControl
): ValidationErrors | null {
  if (control && control.get("highScore") && control.get("lowScore")) {
    const highscore = control.get("highScore").value;
    const lowscore = control.get("lowScore").value;  
    return (lowscore > highscore) ? { scoreError: true } : null
  }
  return null;
}

Затем вы можете удалить ngModel (важно!), так как их нельзя смешивать с реактивными формами. Также вы можете удалить все проверки, такие как required для формы, поэтому в конце ввод может выглядеть просто так:

<input type="number" matInput placeholder="0" formControlName="lowScore">

STACKBLITZ


ОРИГИНАЛ:

Я настоятельно, настоятельно предлагаю реактивные формы , поначалу они могут показаться запутанными, но оно того стоит. У вас есть лучший контроль над формой, и, как упоминалось в комментарии Нитина Кумара Билии, модульное тестирование проще.

Что, как говорится....

Вот решение, использующее форму, управляемую шаблоном, поскольку это то, что вы сейчас используете.

Вы можете сделать директиву, которую вы прикрепите к тегу формы, и внутри этой директивы будет валидатор для сравнения значений highscore и lowscore и прикрепления ошибки к форме или возврата null (что считается действительным в формах). Таким образом, валидатор будет выглядеть так:

import { Directive } from "@angular/core";
import {
  AbstractControl,
  NG_VALIDATORS,
  Validator,
  ValidationErrors
} from "@angular/forms";

@Directive({
  selector: "[scoreValidation]",
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: ScoreValidatorDirective,
      multi: true
    }
  ]
})
export class ScoreValidatorDirective implements Validator {
  constructor() {}

  // here control is the formgroup
  validate(control: AbstractControl): ValidationErrors | null {
    if (control && control.get("highScore") && control.get("lowScore")) {

      // the form controls and their value
      const highscore = control.get("highScore").value;
      const lowscore = control.get("lowScore").value;

      // not valid, return an error
      if (lowscore > highscore) {
        return { scoreError: true };
      }
      // valid
      return null;
    }
    // form controls do not exist yet, return null
    return null;
  }
}

Добавьте директиву в массив объявлений в вашем модуле приложения и используйте ее, просто прикрепив эту директиву к тегу формы:

<form .... scoreValidation>

и ошибка может быть показана с помощью *ngIf="issueThresholdForm.hasError('scoreError')

STACKBLITZ

person AJT82    schedule 29.09.2019
comment
Я согласен, я читал о реактивных формах и, похоже, делает то, что нам нужно, но я бы не хотел создавать для этого совершенно новый компонент в качестве валидатора, я думаю, это будет довольно сложно, поскольку количество валидаторы увеличиваются - person user1712638; 29.09.2019
comment
да, я понимаю, тот же подход для реактивных форм гораздо проще, то есть нужно просто добавить кастомный валидатор как функцию, директиву создавать не надо. Я могу обновить свой ответ, указав вариант того же, что и реактивный подход. - person AJT82; 29.09.2019
comment
@ user1712638, вот, я добавил реактивный подход в свой ответ. Надеюсь, поможет, и это то, что вы хотите сделать :) - person AJT82; 29.09.2019

Я настоятельно рекомендую реактивные формы, но если вы хотите сделать это, вы можете:

поместите следующее p tag под вход lowScore:

<p class="text-danger" [hidden]="(lowerScore.value > higerScore.value ? false: true) || (lowScore.pristine && !issueThresholdForm.submitted)">
                    The lower scrore can not be greater than higer score
</p>
person AbolfazlR    schedule 29.09.2019
comment
К сожалению, это не помешает отправить форму или всю форму или пометить входные данные проблемой, я думаю, что я бы пошел с реактивными формами - person user1712638; 29.09.2019

Вы можете использовать Custom Validations в Reactive Forms следующим образом.

HTML

<div>
  <form [formGroup]="myForm">

    <label>Low Score: </label>
    <input formControlName="lowScore" type="number">
    <br/><br/>
    <label>High Score: </label>
    <input formControlName="highScore" type="number">

    <div>
      <span style="color: red" *ngIf="myForm.get('highScore').touched && myForm.get('highScore').hasError('higherThan')">High score should be higher than lower score.</span>
    </div>

  </form>
</div>

ТС

export class AppComponent  {
  myForm: FormGroup;

  constructor() {

    this.myForm = new FormGroup({
      highScore: new FormControl(0, [this.lowerThan('lowScore')]),
      lowScore: new FormControl(0, null)
    });
  }
  lowerThan(field_name): ValidatorFn {

    return (control: AbstractControl): { [key: string]: any } => {

      const input = control.value;

      const isLower = control.root.value[field_name] >= input;

      return isLower ? {'lowerThan': {isLower}}: null;
    };
  }
}

Найдите рабочий StackBlitz здесь.

person Sudarshana Dayananda    schedule 29.09.2019
comment
Это срабатывает только при запуске формы, а не при ее отправке, что не очень полезно: D, я что-то упустил? - person user1712638; 29.09.2019