为何无法从NgForm中获取表单控件?Angular表单问题
你遇到的这个问题其实是Angular表单初始化时机导致的,我来一步步给你拆解:
1. 为什么无法通过名称访问表单控件?
在ngOnInit钩子执行的时候,Angular还没完成表单控件的注册工作。虽然你用@ViewChild('f')拿到了表单的引用,但此时表单内部的controls对象还没有填充上对应的控件实例——毕竟Angular需要时间去解析模板里的ngModel指令,把输入框和表单控件关联起来。所以这时候你去访问this.form.controls.myname自然会得到undefined。
2. 为什么控制台显示矛盾的结果?
这是浏览器控制台的一个小“特性”:当你打印一个对象的时候,控制台显示的是该对象的引用,而不是打印那一刻的快照。你在ngOnInit里打印this.form.controls时,它确实是空对象{},但当你后来在控制台展开这个对象时,浏览器已经获取到了这个对象的最新状态(此时控件已经注册完成,所以能看到myname键)。而Object.keys(this.form.controls)是在ngOnInit执行时立即计算的,所以返回的是空数组,这才是当时的真实状态。
解决办法
要等到表单控件完全注册完成后再访问,最直接的方式就是使用ngAfterViewInit钩子——这个钩子会在视图及其子视图完全初始化完成后触发,此时表单控件已经被正确注册到form.controls里了:
修改你的组件代码:
export class InputOverviewExample { comment = null; @ViewChild('f') form: NgForm; ngAfterViewInit() { console.log(this.form.controls); console.log(Object.keys(this.form.controls)); // 现在会输出 ["myname"] console.log(this.form.controls.myname); // 能正常获取到控件实例 console.log(this.form.controls['myname']); } }
另外补充一点:你第二个输入框没有使用[(ngModel)]指令,所以Angular不会把它注册到表单的controls集合里,这也是为什么最终只有myname出现在controls中的原因。
内容的提问来源于stack exchange,提问作者Antoniossss

