#angular #angular-material
#angular #angular-material
Вопрос:
Я хочу синхронизировать ползунок с вводимым текстом. Это работает нормально. Также я хочу, чтобы элементы управления обновлялись при возникновении события размытия ( updateon: 'blur'
но я также хочу немедленно обновлять значение formcontrol при изменении ползунка.
https://stackblitz.com/edit/angular-cakpgs
И теперь моя проблема: valuechanges моей формы запускается дважды, когда я меняю значение элемента управления с помощью ползунка. Когда я изменяю значение, я делаю patchValue в формуляре, потому что я хочу немедленно обновить значение. И когда ползунок теряет фокус (событие размытия), уведомление valuechanges запускается снова.
Как я могу сделать, чтобы valuechanges моего formular запускался только один раз, с требованиями, которые:
- formcontrol следует обновлять при возникновении события размытия
updateon: 'blur'
- Изменение значения с помощью ползунка должно быть обновлено немедленно
Ответ №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