#angular #angular2-forms
#угловые #angular2-формы
Вопрос:
У меня есть простая форма, созданная с FormBuilder
:
this.contactForm = formBuilder.group({
'name': [''],
'email': [''],
'phone': [''],
});
Я хочу отслеживать изменения каждого элемента управления и запускать функцию с обновленным значением, когда это произойдет:
getContacts(value: any) {
this.phoneContacts.findContact(value).then(
contacts => {
// do something
}
);
}
Прямо сейчас я делаю это для каждого элемента управления, используя bind
для доступа к this
объекту компонента:
this.contactForm.get('name').valueChanges.subscribe(this.getContacts.bind(this));
this.contactForm.get('email').valueChanges.subscribe(this.getContacts.bind(this));
this.contactForm.get('phone').valueChanges.subscribe(this.getContacts.bind(this));
Есть ли какой-нибудь способ отслеживать изменения и получать обновленное значение только с одной подпиской? Я знаю, что могу подписаться напрямую this.contact.form
, но тогда вместо просто обновленного элемента управления я получаю все элементы управления в качестве значения.
Комментарии:
1. Итак, если я правильно понимаю, вы хотите что-то вроде
this.contactForm.subscribeToUpdated()
?2. Точно! Где
subscribetoUpdated()
я получу значение из последнего измененного ввода
Ответ №1:
Вы можете объединить 3 отдельных наблюдаемых объекта в один, используя оператор слияния. Это даст вам единственную наблюдаемую, которая выдает единственное значение при каждом изменении любого из значений поля формы.
this.contactForm.get('name').valueChanges
.merge(this.contactForm.get('email').valueChanges)
.merge(this.contactForm.get('phone').valueChanges)
Основная проблема с описанным выше подходом заключается в том, что теперь вы не знаете, какое значение соответствует какому элементу управления формой. Одним из решений является отображение изменений значения в другой объект, который содержит как значение, так и элемент управления (т. Е. Источник значения)
// making some local variables for convenience
let name = this.contactForm.get('name')
let email = this.contactForm.get('email'
let phone = this.contactForm.get('phone')
name.valueChanges.map(v => ({control: name,value: v})
.merge(email.valueChanges.map(v => ({control: email, value: v}))
.merge(phone.valueChanges.map(v => ({control: phone, value: v}))
Это даст observable, который генерируется при каждом изменении любого из полей, и значение, которое он генерирует, будет объектом, содержащим значение и элемент управления, который выдал это значение.
Ответ №2:
Вы можете использовать valueChanges для отдельного элемента управления и подписаться на него :
this.contactForm.controls['name'].valueChanges.subscribe((value) => {
console.log(" name : " value)
})
Комментарии:
1. Это то, что я делаю прямо сейчас, но я не хочу делать это отдельно для каждого
FormControl
2. ХОРОШО, итак, вы используете правильный оператор RxJS и объединяете все наблюдаемые в один.
Ответ №3:
Вы можете получить все элементы управления valueChanges, наблюдаемые из формы, и объединить весь поток:
const observablesArray = this.contactFrom.controls.map((control) => control.valueChanges);
Observable.merge(...observablesArray).do(console.log).subscribe();
Теперь вы получаете значение, а не объект со всеми полями при изменении поля.
Комментарии:
1. Я не могу заставить это работать. Не могли бы вы создать StackBlitz? Это было бы ответом и весьма полезным!
Ответ №4:
ngOnInit() {
this.contactForm.valueChanges.subscribe(value => {
console.log(value.name)
});
}
или
вы можете настроить таргетинг на отдельный элемент управления следующим образом,
this.contactForm.controls.name.valueChanges.subscribe(value => {
console.log(value);
});
Комментарии:
1. Внутри подписки я запускаю функцию, которая принимает обновленное значение и что-то с ним делает. Поэтому мне нужно знать, что
FormControl
было обновлено. Это может быть любой из них2. Ваш обновленный ответ — это то, что я уже делаю прямо сейчас, за исключением того, что мне нужно сделать это три раза. Меня интересует, могу ли я сделать только одну подписку на всю
FormGroup
и получить только туFormControl
, которая была обновлена3. Я не знаю, что может быть точным ответом, но вы можете выбрать обходной путь.
4. Да, вы можете. Вы можете использовать мой ответ с объединением, но вам нужно как-то пометить элементы управления, чтобы идентифицировать их. Например, вы можете использовать объекты в качестве значений и ввести некоторый идентификатор элемента управления для этого объекта.