В Angular у меня может быть такая форма:


    
    

    
    

В соответствующем контроллере я мог легко наблюдать за изменениями содержимого этой формы следующим образом:

function($scope) {

    $scope.model = {};

    $scope.$watch('model', () => {
        // Model has updated
    }, true);

}

Вот пример Angular на JSFiddle.

Мне сложно понять, как сделать то же самое в Angular. Очевидно, у нас больше нет $ scope, $ rootScope. Неужели есть метод, с помощью которого можно сделать то же самое?

Вот пример Angular на Plunker.

tambler

Ответов: 6

Ответы (6)

UPD. Ответ и демонстрация обновлены в соответствии с последней версией Angular.


Вы можете подписаться на все изменения формы благодаря тому, что FormGroup, представляющая форму, предоставляет свойство valueChanges, которое является экземпляром Observerable:

this.form.valueChanges.subscribe (data => console.log ('Форма изменяется', данные));

В этом случае вам нужно будет создать форму вручную, используя FormBuilder. Примерно так:

экспортный класс App {
  конструктор (закрытый formBuilder: FormBuilder) {
    this.form = formBuilder.group ({
      firstName: 'Томас',
      lastName: "Манн"
    })

    this.form.valueChanges.subscribe (data => {
      console.log ('Изменения формы', данные)
      this.output = данные
    })
  }
}

Проверить valueChanges в действии в этой демонстрации: http://plnkr.co/edit/xOz5xaQyMlRzSrgtt7Wn?p=preview

Чтобы завершить еще немного предыдущих замечательных ответов, вам нужно знать, что формы используют наблюдаемые для обнаружения и обработки изменений значений. Это что-то действительно важное и мощное. И Марк, и dfsq описали этот аспект в своих ответах.

Observables позволяют не только использовать метод subscribe (что-то похожее на метод обещаний then в Angular 1). При необходимости можно пойти дальше и реализовать некоторые цепочки обработки обновленных данных в формах.

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

this.form.valueChanges
    .debounceTime(500)
    .subscribe(data => console.log('form changes', data));

Вы также можете напрямую подключить обработку, которую хотите запустить (например, асинхронную) при обновлении значений. Например, если вы хотите обработать текстовое значение для фильтрации списка на основе запроса AJAX, вы можете использовать метод switchMap:

this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

Вы даже идете дальше, связывая возвращаемый наблюдаемый объект непосредственно со свойством вашего компонента:

this.list = this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

и отобразить его, используя async pipe:

  • {{elt.name}}

Просто хочу сказать, что вам нужно продумать способ обработки форм по-другому в Angular2 (гораздо более мощный способ; -)).

Надеюсь, это тебе поможет, Тьерри

Расширяем предложения Марка ...

Способ 3

Реализовать «глубокое» обнаружение изменений в модели. Преимущества в первую очередь заключаются в избежании включения аспектов пользовательского интерфейса в компонент; это также фиксирует программные изменения, внесенные в модель. Тем не менее, потребуется дополнительная работа для реализации таких вещей, как устранение неполадок, как предлагает Тьерри, и это также уловит ваши собственные программные изменения, поэтому используйте с осторожностью.

export class App implements DoCheck {
  person = { first: "Sally", last: "Jones" };
  oldPerson = { ...this.person }; // ES6 shallow clone. Use lodash or something for deep cloning

  ngDoCheck() {
    // Simple shallow property comparison - use fancy recursive deep comparison for more complex needs
    for (let prop in this.person) {
      if (this.oldPerson[prop] !==  this.person[prop]) {
        console.log(`person.${prop} changed: ${this.person[prop]}`);
        this.oldPerson[prop] = this.person[prop];
      }
    }
  }

Попробовать в Plunker

Для угловой 5 + версии. Помогает установка версии, поскольку angular вносит много изменений.

ngOnInit() {

 this.myForm = formBuilder.group({
      firstName: 'Thomas',
      lastName: 'Mann'
    })
this.formControlValueChanged() // Note if you are doing an edit/fetching data from an observer this must be called only after your form is properly initialized otherwise you will get error.
}

formControlValueChanged(): void {       
        this.myForm.valueChanges.subscribe(value => {
            console.log('value changed', value)
        })
}
• 100001 забыть что-то с помощью метода 1 или 2.

Немного упрощая метод 3 ...

oldPerson = JSON.parse(JSON.stringify(this.person));

ngDoCheck(): void {
    if (JSON.stringify(this.person) !== JSON.stringify(this.oldPerson)) {
        this.doSomething();
        this.oldPerson = JSON.parse(JSON.stringify(this.person));
    }
}

Вы можете добавить тайм-аут, чтобы вызывать doSomething () только через x миллисекунд, чтобы имитировать дребезг.

oldPerson = JSON.parse(JSON.stringify(this.person));

ngDoCheck(): void {
    if (JSON.stringify(this.person) !== JSON.stringify(this.oldPerson)) {
        if (timeOut) clearTimeout(timeOut);
        let timeOut = setTimeout(this.doSomething(), 2000);
        this.oldPerson = JSON.parse(JSON.stringify(this.person));
    }
}

Если вы используете FormBuilder, см. Ответ @ dfsq.

Если вы не используете FormBuilder, есть два способа получать уведомления об изменениях.

Способ 1

Как обсуждалось в комментариях к вопросу, используйте привязку события к каждому входному элементу. Добавьте в свой шаблон:


Тогда в вашем компоненте:

doSomething(newValue) {
  model.first_name = newValue;
  console.log(newValue)
}

На странице Forms есть дополнительная информация о ngModel, которая актуальна здесь:

ngModelChange не является событием элемента . На самом деле это свойство события директивы NgModel. Когда Angular видит цель привязки в форме [(x)], он ожидает, что директива x будет иметь свойство input x и xChange свойство вывода.

Другая странность - это выражение шаблона, model.name = $ event. Мы привыкли видеть объект $ event, исходящий из события DOM. Свойство ngModelChange не создает событие DOM; это свойство Angular EventEmitter, которое возвращает значение поля ввода при срабатывании ..

Мы почти всегда предпочитаем [(ngModel)]. Мы могли бы разделить привязку, если бы нам нужно было сделать что-то особенное при обработке событий, например, противодействовать или дросселировать нажатия клавиш.

В вашем случае, я полагаю, вы хотите сделать что-то особенное.

Способ 2

Определите локальную переменную шаблона и установите для нее значение ngForm.
Используйте ngControl для элементов ввода.
Получите ссылку на директиву формы NgForm с помощью @ViewChild, затем подпишитесь на ControlGroup NgForm для изменений:

.... ... class MyForm { @ViewChild('myForm') form; ... ngAfterViewInit() { console.log(this.form) this.form.control.valueChanges .subscribe(values => this.doSomething(values)); } doSomething(values) { console.log(values); } }

плункер

Для получения дополнительной информации о методе 2 см. видео Савкина.

См. Также ответ @ Thierry для получения дополнительной информации о том, что вы можете сделать с наблюдаемым valueChanges (например, отладить / немного подождать перед обработкой изменений).

2022 WebDevInsider