如何看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
指令具有x
input属性和xChange
输出属性。另一个奇怪的是模板expression式,
model.name = $event
。 我们习惯于看到来自DOM事件的$event
对象。 ngModelChange属性不会产生DOM事件; 它是一个AngularEventEmitter
属性,它在触发时返回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));
并使用async
pipe道显示它:
<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