Ric*_*nho 6 javascript angular
根据 2017 年 Kara Erickson 在 Angular Connect 上的演讲,我一直在尝试在 Angular 中实现表单投影,但到目前为止没有成功。 谈话链接
不幸的是,唯一可用的代码出现在幻灯片中并且不完整,因此很难解决。这是我尝试过但它抛出错误:https : //stackblitz.com/edit/angular-form-projection-3
表单投影的想法是您有一些包装组件,其模板包含一个<form>元素,并将表单内容投影到其中(演讲中的示例是表单步进器):
<!-- FormStepper -->
<form>
<ng-content></ng-content>
</form>
<!-- containing template, e.g. AppComponent -->
<form-stepper>
<div ngModelGroup="address">
<input name="street" ngModel/>
<input name="city" ngModel/>
</div>
</form-stepper>
Run Code Online (Sandbox Code Playgroud)
像这样的简单实现会导致错误,因为 ngModelGroup 指令期望在表单内,但由于组件边界而无法找到表单指令(ControlContainer 类)。
根据 Kara 的说法,解决方案是从 FormStepperComponent 的提供者提供 ControlContainer 类。使用@ViewChild() 装饰器查询,您可以从组件的视图中获取表单指令并将其存储在实例属性中,例如form.
// within FormStepper
@ViewChild(NgForm) form: NgForm;
Run Code Online (Sandbox Code Playgroud)
然后在提供者数组中,使用 useFactory 为 ControlContainer 配置提供者,以便在请求时返回表单实例:
providers: [
{
provide: ControlContainer,
useFactory: component => {
return component.form;
},
deps: [FormStepperComponent]
}
],
Run Code Online (Sandbox Code Playgroud)
FormStepperComponent 的内容子项中的指令应该能够注入提供者数组中提供的服务。这应该允许 ngModelGroup 获取对其所需表单的引用。
问题是工厂函数在视图初始化之前运行,因此此时 component.form 未定义。
我还创建了这个演示,它演示了内容投影以及视图初始化、内容初始化和工厂运行的顺序。
https://stackblitz.com/edit/angular-projection-experiment
您可以在控制台中看到工厂提供程序在视图初始化之前运行,因此当指令尝试注入它刚刚获取的表单时undefined。
看起来这个演讲中的建议甚至不可能?
您的工厂没有NgForm定义子视图的原因是 NgForm查询将在默认情况下运行更改检测后ViewChild进行查询。您需要更新要在更改检测运行之前运行的 NgForm 查询。这将确保在工厂运行时定义该属性。您可以通过将该属性添加到查询并将其设置为 true 来完成此操作,即ViewChildformstatic
@ViewChild(NgForm, { static: true }) form: NgForm;
Run Code Online (Sandbox Code Playgroud)
ViewChild 上的文档更深入地介绍了此选项:https://angular.io/api/core/ViewChild
我相信当这个演讲进行时,Angular 的 ViewChild 会在默认情况下运行更改检测之前进行查询。此后,Angular 已更新为默认运行更改检测后进行查询。遗憾的是他们没有为本次演讲提供代码示例并使用最新的 Angular 进行更新。
我分叉了你的示例以使其工作:https ://stackblitz.com/edit/angular-projection-experiment-uxzdee
| 归档时间: |
|
| 查看次数: |
219 次 |
| 最近记录: |