Wie kann ich in AngularJS nach Formularänderungen Ausschau halten?

In AngularJS könnte ich ein Formular haben, das folgendermaßen aussieht:

      

Innerhalb des entsprechenden Controllers könnte ich leicht auf Änderungen des Inhalts dieses Formulars achten:

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

Hier ist ein AngularJS-Beispiel für JSFiddle .

Ich habe Probleme herauszufinden, wie man das gleiche in Angular erreichen kann. Offensichtlich haben wir nicht länger $scope , etc …, aber sicherlich gibt es eine Methode, mit der das Gleiche erreicht werden kann.

Hier ist ein Eckiges Beispiel zu Plunker .

UPD. Die Antwort und die Demo werden aktualisiert, um mit dem neuesten Angular übereinzustimmen.


Sie können vollständige Formularänderungen abonnieren, da die FormGroup, die ein Formular darstellt, die Eigenschaft valueChanges bereitstellt, die eine valueChanges Instanz ist:

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

In diesem Fall müssten Sie das Formular manuell mit FormBuilder erstellen . Etwas wie das:

 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 }) } } 

valueChanges Sie sich valueChanges in Aktion in dieser Demo an : http://plnkr.co/edit/xOz5xaQyMlRzSrgtt7Wn?p=preview

Wenn Sie FormBuilder , lesen Sie die Antwort von @ dfsq.

Wenn Sie FormBuilder nicht verwenden, gibt es zwei Möglichkeiten, über Änderungen benachrichtigt zu werden.

Methode 1

Wie in den Kommentaren zu der Frage erläutert, verwenden Sie für jedes Eingabeelement eine Ereignisbindung . Zu deiner Vorlage hinzufügen:

  

Dann in deiner Komponente:

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

Die Formularseite enthält einige zusätzliche Informationen zu ngModel, die hier relevant sind:

Der ngModelChange ist kein -Elementereignis. Es ist tatsächlich eine Ereigniseigenschaft der NgModel Direktive. Wenn Angular ein Bindungsziel in der Form [(x)] sieht, erwartet es, dass die x Direktive eine x Eingabeeigenschaft und eine xChange Ausgabeeigenschaft aufweist.

Die andere Kuriosität ist der Template-Ausdruck model.name = $event . Wir sind es gewohnt, ein $event Objekt zu sehen, das von einem DOM-Ereignis kommt. Die ngModelChange-Eigenschaft erzeugt kein DOM-Ereignis. Es ist eine Angular EventEmitter Eigenschaft, die den Wert des Eingabefeldes zurückgibt, wenn sie EventEmitter wird.

Wir bevorzugen fast immer [(ngModel)] . Wir könnten die Bindung aufteilen, wenn wir etwas Besonderes in der Ereignisbehandlung tun müssen, wie das Entprellen oder das Drosseln der Schlüsselstriche.

In Ihrem Fall nehme ich an, dass Sie etwas Besonderes machen wollen.

Methode 2

Definieren Sie eine lokale Vorlagenvariable und setzen Sie sie auf ngForm .
Verwenden Sie ngControl für die Eingabeelemente.
Rufen Sie mithilfe von @ViewChild einen Verweis auf die NgForm-Direktive des Formulars ab und abonnieren Sie dann die ControlGroup des NgForms für Änderungen:

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

Plünderer

Weitere Informationen zu Methode 2 finden Sie in Savkins Video .

Siehe auch @ Thierrys Antwort für weitere Informationen darüber, was Sie mit den beobachtbaren valueChanges tun können (z. B. Entprellen / warten, bevor Änderungen verarbeitet werden).

Um ein bisschen mehr vorherige große Antworten zu vervollständigen, müssen Sie sich bewusst sein, dass Formulare Observablen nutzen, um Wertänderungen zu erkennen und zu handhaben. Es ist etwas wirklich Wichtiges und Mächtiges. Sowohl Mark als auch dfsq beschrieben diesen Aspekt in ihren Antworten.

Observables ermöglichen nicht nur die Verwendung der subscribe Methode (etwas, das der then Methode der Versprechen in Angular 1 ähnlich ist). Sie können bei Bedarf weitere Schritte ausführen, um einige Verarbeitungsketten für aktualisierte Daten in Formularen zu implementieren.

Ich meine, Sie können auf dieser Ebene die Entprellzeit mit der Methode debounceTime . Auf diese Weise können Sie eine gewisse Zeit warten, bevor Sie mit der Änderung fertig werden und mehrere Eingaben korrekt verarbeiten:

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

Sie können auch die Verarbeitung, die Sie auslösen möchten (z. B. eine asynchrone), wenn Werte aktualisiert werden, direkt einklinken. Wenn Sie beispielsweise einen switchMap behandeln möchten, um eine Liste basierend auf einer AJAX-Anforderung zu filtern, können Sie die Methode switchMap verwenden:

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

Sie gehen noch weiter, indem Sie die zurückgegebene Observable direkt mit einer Eigenschaft Ihrer Komponente verknüpfen:

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

und es mit der async Pipe anzeigen:

 
  • {{elt.name}}

Nur um zu sagen, dass man in Angular2 anders denken muss, um mit Formen umzugehen (viel mächtiger ;-)).

Hoffe es hilft dir, Thierry

Marks Vorschläge erweitern …

Methode 3

Implementieren Sie eine “tiefgreifende” Änderungserkennung am Modell. Die Vorteile umfassen hauptsächlich die Vermeidung der Integration von Benutzerschnittstellenaspekten in die Komponente; Dies erfasst auch programmatische Änderungen am Modell. Das heißt, es würde zusätzliche Arbeit erfordern, um Dinge wie das Entprellen umzusetzen, wie von Thierry vorgeschlagen, und das wird auch Ihre eigenen programmatischen Änderungen einfangen, also verwenden Sie es mit Vorsicht.

 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]; } } } 

Probiere Plunker aus

Ich dachte über die Verwendung der (ngModelChange) -Methode nach, dachte dann über die FormBuilder-Methode nach und entschied mich schließlich für eine Variante von Methode 3. Dies erspart das Dekorieren der Vorlage mit zusätzlichen Attributen und nimmt Änderungen am Modell automatisch auf – wodurch die Möglichkeit, etwas zu vergessen, reduziert wird mit Methode 1 oder 2.

Vereinfachungsmethode 3 ein bisschen …

 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)); } } 

Sie könnten ein Timeout hinzufügen, um doSomething () erst nach x Millisekunden aufzurufen, um Debounce zu simulieren.

 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)); } } 

Für eckige Version 5+ . Putting Version hilft, wie eckig macht viele Änderungen.

 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) }) }