Jul*_*ien 6 typescript angular
我们希望NG_VALUE_ACCESSOR
使用带有ComponentFactoryResolver
和的自定义指令动态地将组件添加到被动表单ViewContainerRef
.问题是我们无法将formControlName分配给动态添加的组件,我们无法从组件中获取访问者值.
我们尝试了几种不同的选项,但它们都没有为我们工作(直接将formControlName添加到ngContainer会引发错误,也是ngComponentOutlet的一个选项,但是我们无法为组件提供参数).
我们在plunker中创建了一个静态测试用例(我们想要达到的结果)和一个使用指令的动态测试用例,我们无法将formControlName分配给组件.我们将在下面的评论中提供链接.
您可以尝试扩展NgControl
。这是简单的实现。但这可能更复杂。
动态面板指令
@Directive({
selector: '[dynamic-panel]'
})
export class DynamicPanelDirective extends NgControl implements OnInit {
name: string;
component: ComponentRef<any>;
@Output('ngModelChange') update = new EventEmitter();
_control: FormControl;
constructor(
@Optional() @Host() @SkipSelf() private parent: ControlContainer,
private resolver: ComponentFactoryResolver,
private container: ViewContainerRef) {
super();
}
ngOnInit() {
let component = this.resolver.resolveComponentFactory<GeneralPanelComponent>(GeneralPanelComponent);
this.name = 'general';
this.component = this.container.createComponent(component);
this.valueAccessor = this.component.instance;
this._control = this.formDirective.addControl(this);
}
get path(): string[] {
return [...this.parent.path !, this.name];
}
get formDirective(): any { return this.parent ? this.parent.formDirective : null; }
get control(): FormControl { return this._control; }
get validator(): ValidatorFn|null { return null; }
get asyncValidator(): AsyncValidatorFn { return null; }
viewToModelUpdate(newValue: any): void {
this.update.emit(newValue);
}
ngOnDestroy(): void {
if (this.formDirective) {
this.formDirective.removeControl(this);
}
if(this.component) {
this.component.destroy();
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以
如何动态地将NG_VALUE_ACCESSOR组件添加到反应形式?
this.valueAccessor = this.component.instance;
Run Code Online (Sandbox Code Playgroud)
就我而言
如果要使用验证器,请参阅此柱塞
当前接受的答案适用于原始帖子中的确切场景,但稍微不同的场景让我看到了这篇文章。感谢@yurzui,我能够根据他的回答找到解决方案。
我自己的解决方案允许使用模板中常用的声明性绑定将(包括 ngModel、反应式表单和验证器)完全集成到 Angular 表单生态系统中。所以我把它贴在这里,以防其他人来这里找这个。
您可以在StackBlitz上查看。
import {
Component,
ComponentFactoryResolver,
forwardRef,
Host,
Injector,
SkipSelf,
ViewContainerRef,
} from '@angular/core';
import { ControlContainer, NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { CustomInputComponent } from './custom-input.component';
@Component({
selector: 'app-form-control-outlet',
template: ``,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormControlOutletComponent),
multi: true,
},
],
})
export class FormControlOutletComponent {
constructor(
public injector: Injector,
private componentFactoryResolver: ComponentFactoryResolver,
private viewContainerRef: ViewContainerRef,
) {}
public ngOnInit(): void {
const ngControl = this.injector.get(NgControl);
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
/**
* Retrieve this component in whatever way you would like,
* it could be based on an @Input or from a service etc...
*/
CustomInputComponent,
);
const componentRef = this.viewContainerRef.createComponent(
componentFactory,
);
ngControl.valueAccessor = componentRef.instance;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
905 次 |
最近记录: |