Проверка формы (угловая) - PullRequest
0 голосов
/ 24 января 2019

Я использую угловую реактивную форму и создаю поля ввода расстояния, которые имеют два поля ввода, называемые From и To.

HTML:

<form [formGroup]="form">
  <button (click)="addRow()">Add</button>
  <div formArrayName="distance">
    <div
      *ngFor="let item of form.get('distance').controls; let i = index"
      [formGroupName]="i"
      style="display: flex"
    >
      <input type="number" placeholder="From" formControlName="from" />
      <div><input type="number" placeholder="To" formControlName="to" /></div>
    </div>
  </div>
  <br /><br />
  <button type="submit" [disabled]="!form.valid">Submit</button>
</form>

Машинопись:

ngOnInit() {
  this.form = this.fb.group({
    distance: this.fb.array([]),
  });
  this.addRow()
}

addRow() {
  const control = this.form.controls.distance as FormArray;
  control.push(this.fb.group({
    from: ['',Validators.required],
    to: ['',Validators.required]
  }));
}

Здесь вы можете увидеть два поля ввода по умолчанию как from и to.

Вверху есть кнопка добавления, и после нажатия кнопки добавления строки с одинаковыми полями ввода добавляются и образуют массив.

Здесь я нуждаюсь в ограничении, чтобы пользователь не позволял вводить значение в предыдущей строки, а также не меньшее значение.

Например,

В первой строке, если пользователь вводит следующие значения, такие как 0 и 5 для от и до соответственно

  "distance": [
    {
      "from": 0,
      "to": 5
    }
  ]

После нажатия кнопки «Добавить» и во второй строке в С в поле ввода пользователь должен быть ограничен при добавлении значений 5 и меньше, чем это (что означает, что эти значения уже были введены).

Так как это неверно,

{
  "distance": [
    {
      "from": 0,
      "to": 5
    },
    {
      "from": 5,
      "to": 10
    }
  ]
}

Здесь "from": 5, или "from": 4(or)3(or)2(or)1, что-то недопустимо во втором ряду ..

Допустимо только 6 и больше 6.

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

Пожалуйста, помогите мне достичь этого типа проверки, ограничивающей пользователя не вводить предыдущую строку значением (или) меньшим, чем в текущей строке от значения.

Рабочий пример: https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-j58atx

Edit:

Пробовал с изменением ввода, как,

<input type="number" (input)="onInputChange($event.target.value)" placeholder="From" formControlName="from">

в ссылке https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-ymfpkj но не уверен, правильно ли я иду ..

Пожалуйста, измените, если эта процедура неправильная.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Наконец я решил разделить два условия.см. new stackblitz

  ngOnInit() {
    this.form = this.fb.group({
      distance: this.fb.array([], this.distanceValidator()),
    });
    this.addRow()
  }

  addRow() {
    const control = this.form.controls.distance as FormArray;
    control.push(this.fb.group({
      from: ['', Validators.required],
      to: ['', Validators.required]
    }, { validator: this.greaterValidator() }));
  }
  setDefault() {
    const control = this.form.controls.distance as FormArray;
    this.default.forEach(data => {
      control.push(this.fb.group({
        from: [data.from, Validators.required],
        to: [data.to, Validators.required]
      }, { validator: this.greaterValidator() }));
    });
  }
  greaterValidator() {
    return (fa: FormGroup) => {
      return fa.value.to && fa.value.to < fa.value.from ? { error: "from greater than to" } : null;
    }
  }
  distanceValidator() {
    return (fa: FormArray) => {
      let ok = true;
      for (let i = 1; i < fa.value.length; i++) {
        ok = (!fa.value[i].from || fa.value[i].from > fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > fa.value[i - 1].from);
        if (!ok)
          return { error: "from/to yet included", index: i }
      }
      return null
    }
  }

И .html

<form [formGroup]="form">
    <button (click)="addRow()">Add</button>
  <div formArrayName="distance" >
    <div 
      *ngFor="let item of form.get('distance').controls; let i = index" 
      [formGroupName]="i" 
      style="display: flex">
      <input type="number" 
        placeholder="From" 
        formControlName="from">
      <div>
        <input type="number"
          placeholder="To" 
          formControlName="to">
      </div>
      <span *ngIf="item.errors">*</span>
      <span *ngIf="form.get('distance')?.errors && form.get('distance')?.errors.index==i">**</span>
    </div>
  </div>
  <div *ngIf="form.get('distance')?.errors">{{form.get('distance')?.errors.error}}</div>
  <br><br>
  <button type="submit" [disabled]="!form.valid"> Submit </button>
</form>
<button (click)="setDefault()"> Set Default Values </button>

Обновление : на самом деле только тогда, когда обнаружена ошибка, больше не контролируется.Более того, если from и to before пустые, не выдают ошибку.Во избежание этого мы можем «преобразовать» в число, написав

let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to)
        && (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);

(см. «+» В + fa.value [i-1] .to и + fa.value [i-1]).из

Итак, поскольку мы решили отправленную нами ошибку, представьте, что у вас есть 6 строк, и строка в позиции 0, в позиции 3 и в позиции 4 (0 - это первая строка) отправляет ошибку наподобие

{error:"there are errors",indexError:",0,3,4,"}

Это позволяет в * ngFor писать что-то вроде

  <span *ngIf="form.get('distance')?.errors && 
      form.get('distance')?.errors.indexError.indexOf(','+i+',')>=0">
       **
  </span>

Ну, наш distanceValidator становится похожим на

  distanceValidator() {
    return (fa: FormArray) => {
      let indexError:string="";
      for (let i = 1; i < fa.value.length; i++) {
        let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
        if (!ok)
          indexError+=','+i;
      }
      return indexError?{error:"there are errors",indexError:indexError+','}:null
    }

Кто-то может подумать, что лучше вернуть массив ошибок, но это не разрешено, так как легко узнать строку с ошибками. Некоторые, например, errors.find (x => x.id == i) не работают, потому что мы не можем использовать find в интерполяции.

Это правда, что сравнивайте только одну строку с промежуточным значением ранее. Можно проверить все перед тем, как использовать - for (пусть j = i-1; j> 0; j ++) {ok = ok && ...} -, ноЯ думаю, что это не обязательно, и мы должны быть скупы в коде. Помните, что функция distanceValidator выполняется несколько раз. См. Еще stackblitz

0 голосов
/ 24 января 2019

Просто используйте customValidation (я выбираю проверку в том же компоненте

ngOnInit() {
    this.form = this.fb.group({
      distance: this.fb.array([], this.distanceValidator()),
    });
    this.addRow()
  }
  distanceValidator() {
    return (fa: FormArray) => {
      let ok = true;
      let ok2 = fa.value.length ? (!fa.value[0].to || !fa.value[0].from) || fa.value[0].to > fa.value[0].from : true;
      if (!ok2)
        return { error: "from greater than to" }
      for (let i = 1; i < fa.value.length; i++) {
        if (fa.value[i].from && fa.value[i].to )
        {
        ok = (fa.value[i].from > fa.value[i - 1].to || fa.value[i].to < fa.value[i - 1].from);
        ok2 = (fa.value[i].to > fa.value[i].from);
        if (!ok)
          return { error: "from/to yet included" }
        if (!ok2)
          return { error: "from greater than to" }
        }
      }
      return ok && ok2 ? null : !ok?{ error: "from yet included" }:{ error: "from greater than to" }
    }
  }

. Вы можете увидеть ошибку как другую

 <div *ngIf="form.get('distance')?.errors">
     {{form.get('distance')?.errors.error}}
 </div>

см. [Stackblitz разветвлено] [1]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...