如何看Angular 2中的表单变化?

如何看Angular 2中的表单变化?

在Angular 1.x中,我可能有一个如下所示的表单:

<ng-form> <label>First Name</label> <input type="text" ng-model="model.first_name"> <label>Last Name</label> <input type="text" ng-model="model.last_name"> </ng-form> 

在相应的控制器中,我可以很容易地观察到表单内容的变化,如下所示:

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

这里是JSFiddle的一个例子 。

我很难找出如何在Angular 2中完成同样的事情。显然,我们不再有$scope等等,但是肯定有一种方法可以完成同样的事情呢?

这是一个Plunker的2.X例子 。

UPD。 答案和演示更新,以配合最新的Angular。


您可以订阅整个表单更改,因为表单FormGroup提供了valueChanges属性,它是一个可观察的实例:

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

在这种情况下,您需要使用FormBuilder手动构build表单。 像这样的东西:

 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的操作: http : //plnkr.co/edit/xOz5xaQyMlRzSrgtt7Wn?p=preview

如果您使用FormBuilder ,请参阅@ dfsq的答案。

如果您没有使用FormBuilder ,则有两种方法可以通知更改。

方法1

正如在问题的评论中所讨论的那样,在每个input元素上使用一个事件绑定 。 添加到您的模板:

 <input type="text" class="form-control" required [ngModel]="model.first_name" (ngModelChange)="doSomething($event)"> 

然后在你的组件中:

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

Forms页面有一些关于ngModel的附加信息,在这里是相关的:

ngModelChange不是一个<input>元素事件。 它实际上是NgModel指令的事件属性。 当Angular以[(x)]的forms看到绑定目标时,它期望x指令具有xinput属性和xChange输出属性。

另一个奇怪的是模板expression式, model.name = $event 。 我们习惯于看到来自DOM事件的$event对象。 ngModelChange属性不会产生DOM事件; 它是一个Angular EventEmitter属性,它在触发时返回input框的值。

我们几乎总是比较喜欢[(ngModel)] 。 如果我们不得不在事件处理方面做一些特殊的事情,比如反弹或者敲击关键敲击,我们可能会拆分绑定。

就你而言,我想你想做一些特别的事情。

方法2

定义一个本地模板variables并将其设置为ngForm
在input元素上使用ngControl。
使用@ViewChild获取表单的NgForm指令的引用,然后订阅NgForm的ControlGroup以进行更改:

 <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

有关方法2的更多信息,请参阅Savkin的video 。

另请参阅@ Thierry的答案,以获取有关valueChanges可观察性(例如在处理更改之前进行反弹/等待一些操作)的更多信息。

为了完成一些更好的答案,你需要知道表单利用observables来检测和处理值的变化。 这是非常重要和强大的东西。 马克和dfsq在他们的答案中描述了这个方面。

Observable不仅允许使用subscribe方法(类似于Angular 1中的promise方法)。 如果需要,可以进一步实施一些处理链,以更新表单中的数据。

我的意思是你可以在这个级别用debounceTime方法指定去抖时间。 这允许您在处理更改之前等待一段时间,并正确处理多个input:

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

更新值时,您也可以直接插入想要触发的处理(例如某些asynchronous处理)。 例如,如果要处理文本值以基于AJAX请求筛选列表,则可以使用switchMap方法:

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

您甚至可以通过将返回的observable直接链接到组件的属性来进一步:

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

并使用asyncpipe道显示它:

 <ul> <li *ngFor="#elt of (list | async)">{{elt.name}}</li> </ul> 

只是说,你需要考虑如何在Angular2中以不同的方式处理表单(一种更强大的方法;-))。

希望它能帮助你,Thierry

扩大Mark的build议…

方法3

在模型上实现“深度”变化检测。 优点主要涉及避免将用户界面方面结合到组件中; 这也捕捉对模型进行的程序化改变。 也就是说,需要额外的工作去实施像Thierry所提出的去抖动这样的事情,而且这也会引起你自己的程序变化,所以要谨慎使用。

 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