Mat-slide: одно изменение дважды увеличивает подписку на valuechanges

#angular #angular-material

#angular #angular-material

Вопрос:

Я хочу синхронизировать ползунок с вводимым текстом. Это работает нормально. Также я хочу, чтобы элементы управления обновлялись при возникновении события размытия ( updateon: 'blur' но я также хочу немедленно обновлять значение formcontrol при изменении ползунка.

https://stackblitz.com/edit/angular-cakpgs

И теперь моя проблема: valuechanges моей формы запускается дважды, когда я меняю значение элемента управления с помощью ползунка. Когда я изменяю значение, я делаю patchValue в формуляре, потому что я хочу немедленно обновить значение. И когда ползунок теряет фокус (событие размытия), уведомление valuechanges запускается снова.

Как я могу сделать, чтобы valuechanges моего formular запускался только один раз, с требованиями, которые:

  1. formcontrol следует обновлять при возникновении события размытия updateon: 'blur'
  2. Изменение значения с помощью ползунка должно быть обновлено немедленно

Ответ №1:

Я сделал следующее:

 this.form.valueChanges
.pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)))
.subscribe(change => console.log(change));
  

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

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

1. в моем проекте запускался дважды, потому что использование ng-trim-value-accessor .сработало для меня!

2. Это работает так, как ожидалось в Angular 10. Спасибо.

Ответ №2:

Если у вас уже есть FormControls, тогда ничего не нужно делать [value]="AgeControl.value" , пусть значение обновляется только через FormControl… Поскольку мы хотим обнаруживать изменения при каждом вводе (тип: ползунок или текст), а затем реплицировать, мы добавили (change) для всех входов.

Чтобы сделать обновление более быстрым, я добавил третий ввод прямо внизу формы, который вносит эти изменения при каждом нажатии клавиши, и получать больше удовольствия от просмотра такого обновления с помощью <input /> . Надеюсь, это то, что вы ищете.

В вашем существующем stackblitz укажите ваш hello-component.ts как:

 import { Component, OnInit, OnChanges } from '@angular/core';
// Must import to use Forms functionality  
import { FormBuilder, FormGroup, Validators, FormsModule, NgForm, FormControl } from '@angular/forms';

@Component({
  selector: 'app-hello-component',
  templateUrl: './hello-component.component.html',
  styleUrls: ['./hello-component.component.css']
})
export class HelloComponentComponent implements OnInit, OnChanges {

  form: FormGroup;

  constructor(private fb: FormBuilder) {
    // To initialize FormGroup  
    this.form = fb.group({
      'age': [null, { updateOn: 'blur' }]
    });
    this.form.valueChanges.subscribe(change => console.log(change));
  }

  ngOnInit() {
    this.AgeControl.setValue(10);
  }
  ngOnChanges() {
    console.log('change triggered');
  }

  public get AgeControl(): FormControl {
    return this.form.get('age') as FormControl;
  }
  onInputChange(event: any) {
    //value must change immediately
    this.form.patchValue({ 'age': event.target.value });
  }
  onSliderChange(event: any) {
    this.form.patchValue({ 'age': event.value });
  }
  onInputKeystroke(event: any) {
    this.form.patchValue({ 'age': event.target.value });
  }

}
  

В вашем существующем stackblitz укажите свой hello-component.html должно быть:

 <mat-slider thumbLabel tickInterval="1" min="1" [formControl]="AgeControl" (change)="onSliderChange($event)" max="100">
</mat-slider>
<br/>
<input [formControl]="AgeControl" (change)="onInputChange($event)">
<br/>
<input [formControl]="AgeControl" (change)="onInputChange($event)">
<pre>{{ form.value | json }}</pre>
<input [formControl]="AgeControl" (keyup)="onInputKeystroke($event)">
  

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

1. Здесь: this.form.valueChanges.subscribe(change => console.log(change)); функция подписчика console.log(change) вызывается еще дважды, когда я меняю значение с помощью ползунка: в onSliderChange и в, когда ползунок теряет фокус

2. Вы получаете двойную консоль. войти с кодом, которым я поделился?

3. Да, когда ползунок теряет фокус, появляется другая консоль.log