Angular 2 — получить значение измененного FormControl в наблюдаемом

#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. Да, вы можете. Вы можете использовать мой ответ с объединением, но вам нужно как-то пометить элементы управления, чтобы идентифицировать их. Например, вы можете использовать объекты в качестве значений и ввести некоторый идентификатор элемента управления для этого объекта.