Angular 8跨组件填充表单问题:setValue不生效求助
问题:Angular组件间表单赋值不生效,原生DOM赋值正常
我尝试从HomeComponent向InserimentoComponent填充表单。在HomeComponent中实例化了InserimentoComponent对象,调用其方法时console.log正常,但使用setValue设置表单值后,页面上无法显示。调试发现值已正确传递,改用原生DOM赋值则可正常显示。
HomeComponent 代码
export class HomeComponent implements OnInit { public inserimentoComponent: InserimentoComponent; constructor(private channelService: ChannelService, private flowService: FlowService, private router: Router, private wizardService: WizardService, public fb: FormBuilder) { } ngOnInit() { this.inserimentoComponent = new InserimentoComponent(this.wizardService, this.flowService, this.fb); this.inserimentoComponent.formInserimento = this.fb.group({ matricola: new FormControl('', Validators.required), name: new FormControl('', Validators.required), }) } goToInserimento(id: any): void { this.router.navigate(['/wizard']); const delay = new Promise(resolve => setTimeout(resolve, 500)); delay.then(() => { const linkElement = document.querySelector('a[routerLink="inserimento"]') as HTMLElement; if (linkElement) { linkElement.click(); } }); delay.then(() => { this.inserimentoComponent.getInserimentoById(id) }); } }
InserimentoComponent 代码
export class InserimentoComponent implements OnInit { //Inizializza il form public formInserimento: FormGroup; constructor (private wizardService: WizardService, private flowService: FlowService, public fb: FormBuilder) { this.formInserimento = this.fb.group({ matricola: new FormControl('', Validators.required), name: new FormControl('', Validators.required), }) } getInserimentoById(id) { console.log(id) //it works this.wizardService.getInserimentoById(id).subscribe(response => { this.inserimento = response.result; //it works console.log(response.result) if (response.result != null) { //it works this.formInserimento.controls['matricola'].setValue(this.inserimento.matricola); //it doesn't work this.formInserimento.controls['name'].setValue(this.inserimento.name); //it doesn't work }); } }
错误原因
你在HomeComponent里手动new出来的InserimentoComponent实例,和路由导航后页面上渲染的实际组件实例完全不是同一个对象。Angular的组件实例由框架负责创建和管理,手动实例化的组件没有和DOM绑定,所以你给这个实例的表单赋值,根本不会同步到页面上的真实表单。
解决建议
方案1:通过路由传递ID,在目标组件内加载数据
这是最符合Angular规范的做法:
- 修改
goToInserimento方法,把ID通过路由参数传递:
goToInserimento(id: any): void { this.router.navigate(['/wizard/inserimento'], { queryParams: { id } }); }
- 在
InserimentoComponent中监听路由参数,自动加载数据:
import { ActivatedRoute } from '@angular/router'; export class InserimentoComponent implements OnInit { public formInserimento: FormGroup; private inserimento: any; constructor( private wizardService: WizardService, private flowService: FlowService, public fb: FormBuilder, private route: ActivatedRoute // 注入ActivatedRoute ) { this.formInserimento = this.fb.group({ matricola: new FormControl('', Validators.required), name: new FormControl('', Validators.required), }) } ngOnInit() { // 监听路由参数变化 this.route.queryParams.subscribe(params => { const id = params['id']; if (id) { this.getInserimentoById(id); } }); } getInserimentoById(id) { this.wizardService.getInserimentoById(id).subscribe(response => { this.inserimento = response.result; if (this.inserimento != null) { this.formInserimento.patchValue({ matricola: this.inserimento.matricola, name: this.inserimento.name }); } }); } }
方案2:使用服务共享数据
创建一个共享服务来存储需要传递的数据,HomeComponent设置数据,InserimentoComponent订阅获取:
- 创建共享服务:
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class DataShareService { private inserimentoIdSubject = new BehaviorSubject<number | null>(null); inserimentoId$ = this.inserimentoIdSubject.asObservable(); setInserimentoId(id: number) { this.inserimentoIdSubject.next(id); } }
- 在
HomeComponent中使用:
constructor( // ...其他依赖 private dataShareService: DataShareService ) {} goToInserimento(id: any): void { this.dataShareService.setInserimentoId(id); this.router.navigate(['/wizard/inserimento']); }
- 在
InserimentoComponent中订阅:
constructor( // ...其他依赖 private dataShareService: DataShareService ) {} ngOnInit() { this.dataShareService.inserimentoId$.subscribe(id => { if (id) { this.getInserimentoById(id); } }); }
方案3:避免手动实例化组件(不推荐)
如果你坚持要保留现有导航逻辑,绝对不要手动new组件,而是通过ViewChild或者组件容器获取真实的组件实例,但这种方式耦合度极高,不建议在路由场景下使用。
内容的提问来源于stack exchange,提问作者JDev
相关产品推荐
相关产品推荐

