The ValueChanges is an event raised by the Angular forms whenever the value of the FormControl, FormGroup or FormArray changes. It returns an observable so that you can subscribe to it. The observable gets the latest value of the control. It allows us to track changes made to the value in real-time and respond to it.
ng-touched will be applied if the condition is true and ng-untouched will be applied if false. This pair of classes defines the state of the control whether its value has been changed or not. ng-dirty will be applied if the condition is true and ng-pristine will be applied if false.
NgForm is used to create a top-level form group Instance, and it binds the form to the given form value.
UPD. The answer and demo are updated to align with latest Angular.
You can subscribe to entire form changes due to the fact that FormGroup representing a form provides valueChanges
property which is an Observerable instance:
this.form.valueChanges.subscribe(data => console.log('Form changes', data));
In this case you would need to construct form manually using FormBuilder. Something like this:
export class App {
constructor(private formBuilder: FormBuilder) {
this.form = formBuilder.group({
firstName: 'Thomas',
lastName: 'Mann'
})
this.form.valueChanges.subscribe(data => {
console.log('Form changes', data)
this.output = data
})
}
}
Check out valueChanges
in action in this demo: http://plnkr.co/edit/xOz5xaQyMlRzSrgtt7Wn?p=preview
If you are using FormBuilder
, see @dfsq's answer.
If you are not using FormBuilder
, there are two ways to be notified of changes.
Method 1
As discussed in the comments on the question, use an event binding on each input element. Add to your template:
<input type="text" class="form-control" required [ngModel]="model.first_name"
(ngModelChange)="doSomething($event)">
Then in your component:
doSomething(newValue) {
model.first_name = newValue;
console.log(newValue)
}
The Forms page has some additional information about ngModel that is relevant here:
The
ngModelChange
is not an<input>
element event. It is actually an event property of theNgModel
directive. When Angular sees a binding target in the form[(x)]
, it expects thex
directive to have anx
input property and anxChange
output property.The other oddity is the template expression,
model.name = $event
. We're used to seeing an$event
object coming from a DOM event. The ngModelChange property doesn't produce a DOM event; it's an AngularEventEmitter
property that returns the input box value when it fires..We almost always prefer
[(ngModel)]
. We might split the binding if we had to do something special in the event handling such as debounce or throttle the key strokes.
In your case, I suppose you want to do something special.
Method 2
Define a local template variable and set it to ngForm
.
Use ngControl on the input elements.
Get a reference to the form's NgForm directive using @ViewChild, then subscribe to the NgForm's ControlGroup for changes:
<form #myForm="ngForm" (ngSubmit)="onSubmit()">
....
<input type="text" ngControl="firstName" class="form-control"
required [(ngModel)]="model.first_name">
...
<input type="text" ngControl="lastName" class="form-control"
required [(ngModel)]="model.last_name">
class MyForm {
@ViewChild('myForm') form;
...
ngAfterViewInit() {
console.log(this.form)
this.form.control.valueChanges
.subscribe(values => this.doSomething(values));
}
doSomething(values) {
console.log(values);
}
}
plunker
For more information on Method 2, see Savkin's video.
See also @Thierry's answer for more information on what you can do with the valueChanges
observable (such as debouncing/waiting a bit before processing changes).
To complete a bit more previous great answers, you need to be aware that forms leverage observables to detect and handle value changes. It's something really important and powerful. Both Mark and dfsq described this aspect in their answers.
Observables allow not only to use the subscribe
method (something similar to the then
method of promises in Angular 1). You can go further if needed to implement some processing chains for updated data in forms.
I mean you can specify at this level the debounce time with the debounceTime
method. This allows you to wait for an amount of time before handling the change and correctly handle several inputs:
this.form.valueChanges
.debounceTime(500)
.subscribe(data => console.log('form changes', data));
You can also directly plug the processing you want to trigger (some asynchronous one for example) when values are updated. For example, if you want to handle a text value to filter a list based on an AJAX request, you can leverage the switchMap
method:
this.textValue.valueChanges
.debounceTime(500)
.switchMap(data => this.httpService.getListValues(data))
.subscribe(data => console.log('new list values', data));
You even go further by linking the returned observable directly to a property of your component:
this.list = this.textValue.valueChanges
.debounceTime(500)
.switchMap(data => this.httpService.getListValues(data))
.subscribe(data => console.log('new list values', data));
and display it using the async
pipe:
<ul>
<li *ngFor="#elt of (list | async)">{{elt.name}}</li>
</ul>
Just to say that you need to think the way to handle forms differently in Angular2 (a much more powerful way ;-)).
Hope it helps you, Thierry
For angular 5+
version. Putting version helps as angular makes lot of changes.
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)
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With