是否可以获得formControl的本机元素?
Posted
技术标签:
【中文标题】是否可以获得formControl的本机元素?【英文标题】:Is it possible to get native element for formControl? 【发布时间】:2017-01-31 05:43:18 【问题描述】:我有 Angular reactive form。我创建了formControl
s 并将其分配给[formControl]=...
的输入字段。据我了解,它会创建 nativeElement <-> formControl
链接。
我的问题:formControl
可以得到nativeElement
吗?我想做类似myFormControl.nativeElement.focus()
【问题讨论】:
你能显示一些代码吗?告诉我们您想要的位置和方式? 更新了问题描述 但是当你想集中注意力的时候呢?那是小鬼。 你有一个或多个表单控件吗? 【参考方案1】:我可以分享一个糟糕的解决方案,但它对我有用。
在反应形式中,我们可以使用任何一种
1) FormControlDirective
ts
myControl = new FormControl('')
模板
<input type="text" [formControl]="myControl">
或
2) FormControlName
ts
myForm: FormGroup;
constructor(private fb: FormBuilder)
ngOnInit()
this.myForm = this.fb.group(
foo: ''
);
模板
<form [formGroup]="myForm">
<input type="text" formControlName="foo">
</form>
所以对于这些指令我可以写一些补丁,比如
1) FormControlDirective
const originFormControlNgOnChanges = FormControlDirective.prototype.ngOnChanges;
FormControlDirective.prototype.ngOnChanges = function()
this.form.nativeElement = this.valueAccessor._elementRef.nativeElement;
return originFormControlNgOnChanges.apply(this, arguments);
;
2) FormControlName
const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges;
FormControlName.prototype.ngOnChanges = function()
const result = originFormControlNameNgOnChanges.apply(this, arguments);
this.control.nativeElement = this.valueAccessor._elementRef.nativeElement;
return result;
;
之后我们可以轻松访问具有FormControl
实例的原生元素
1) FormControlDirective
focusToFormControl()
(<any>this.myControl).nativeElement.focus();
2) FormControlName
focusToFormControlName(name)
(<any>this.myForm.get(name)).nativeElement.focus();
Plunker Example
【讨论】:
嗨,我在组件类的顶部添加了原型,但我收到一个错误,即this.valueAccessor._elementRef
在 FormControlName
中未定义。【参考方案2】:
下面的代码不适用于纯 ngModel 绑定,所以我做了很多实验。最新的,Maximilian Schwarzmuller 也证实应该是这个:
@Directive(
selector: '[ngModel], [formControl]', // or 'input, select, textarea' - but then your controls won't be handled and also checking for undefined would be necessary
)
export class NativeElementInjectorDirective
constructor(private el: ElementRef, private control : NgControl, @Optional() private model : NgModel)
if (!! model)
(<any>model.control).nativeElement = el.nativeElement;
else
(<any>control).nativeElement = el.nativeElement;
因此,如果在主模块中提供并导出此指令,它将为所有 FormControl 附加一个自定义的 nativeElement 属性。
很遗憾它不是开箱即用的......
【讨论】:
用法不清楚,如果您只是简单地将该指令导入到主模块,它会自动提供nativeElement属性吗?我的表单控件无法识别该属性,并且没有关于属性完成/预测的建议。最好发布如何使用您的指令 @Shift'NTab 不管它是我的还是其他人的或角度指令,它们的使用方式相同。如果您在自定义模块中声明该指令,则需要将其导入到您要使用它的模块中。或者只是在你的模块中声明它并将类添加到模块的声明数组中。一旦那里它会自动执行。如果您不相信,您可以将调试器放入 ctor 中。 @Shift'NTab 所以,简而言之:在你实现(声明)指令的地方创建一个模块,并确保你也导出它。然后只需将模块包含在您需要的地方。就是这样。 ok 再次回到这里(<any>control.control).nativeElement
有一个错误,因为控制台中的 control.control 返回未定义。这会阻止您分配动态属性。
@LeonardoX 更新了***.com/a/49462046/4524989,所以它现在应该可以工作了,问题是原始样本是用于模板驱动的方法,其中 NgModel 被注入到控件中,而通过模型驱动,你会得到直接的 NgControl给定的输入。只需查看更新。顺便提一句。感谢 StackBlitz,很抱歉花了 5 天时间(有很多工作):) 使用该调试,它对我有很大帮助...【参考方案3】:
为 baHI 答案添加了小修复(将逻辑移至 OnInit)。 cmets中提到的错误可能与表格的变化有关。此答案适用于 "@angular/forms": "~7.1.0",
@Directive(
selector: '[ngModel]'
)
export class NativeElementInjectorDirective implements OnInit
constructor (private el: ElementRef, private control : NgControl)
ngOnInit()
(this.control.control as any).nativeElement = this.el.nativeElement;
【讨论】:
这适用于我们在角度 6 上:D 唯一需要的更改是“选择器:[formControlName]”谢谢!!【参考方案4】:是的,您必须使用[formControl], [formControlName]
选择器编写指令。
完整示例:
import Directive, ElementRef from "@angular/core";
import NgControl from '@angular/forms';
@Directive(
selector: '[formControl], [formControlName]'
)
export class ControlErrorsDirective
get control()
return this.controlDir.control;
constructor(
private controlDir: NgControl,
private host: ElementRef<htmlFormElement>)
ngOnInit()
console.log(this.host.nativeElement);
在你的 html 中使用 formControlName
像这样:<input formControlName='name' />
【讨论】:
我使用此代码为每个表单控件添加动态错误消息。 不链接表单控件相关的原生元素如何获取? 这个想法(见我的回答 - 15 个赞成票)很简单:使用一个指令来简单地扩展角度控制对象和一个额外的 nativeElement 属性。从那时起,如果您引用该控件,您也可以访问该属性。但您可能只需要一个模板参考!? 为什么需要两个选择器?我发现只有一个选择器:“[formControlName]”有效。一个实际的选择器 formControl 不起作用。【参考方案5】:你好,谁读到这里!我希望你和我玩 Angular 一样开心:)
我花了一点时间处理一个相关问题,导致我来到这里。 在我看来,“injector”指令解决方案是一种解决方法,也是一种解决问题的不可预测的方式。
我怀疑 Angular 团队可能有他们的理由说明这不是“开箱即用”的。也许他们不想将 FormControl 绑定到一个确切的 DOM 元素,因为这两个元素可以相互寿命更长或被删除(在本机元素的情况下),或被克隆(不会复制“扩展”分配,并且,因此,有效地丢失了针对原始 DOM 元素和 FormControl 对象的先前克隆的指令的任何分配)等。
经过一番思考,我选择了这个解决方案:
// Get the first invalid formControlName to scroll to:
const firstInvalidField =
Object.keys(form.controls).find(field => form.get(field)?.invalid);
// My DOM element query selector string
const selector = `[formControlName=$firstInvalidField]`;
console.log(
document.querySelector( $selector )`
);
现在我保证我将获得对 DOM 元素的引用。
【讨论】:
此解决方案不支持嵌套 formGroups 或表单控件数组。感谢您的努力 @user2599470 这是非常合理的方向......而且完全有道理。虽然 document.querySelector 在 Angular 的上下文中感觉很hackish。【参考方案6】:在模板上创建一个输入字段:
<input matInput formControlName="cardnumber" #cardnumber >
在类中获取它的viewchild:
@ViewChild("cardnumber") cardnumberField: FormControl;
初始化:
this.cardnumberField = new FormControl(null, []);
随心所欲:
(<any> this.cardnumberField).nativeElement.value = "";
(<any> this.cardnumberField).nativeElement.focus();
【讨论】:
以上是关于是否可以获得formControl的本机元素?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 2.0 中使用 formControl 访问 Native HTML Input 元素
Angular FormControl valueChanges 不起作用
获取 FormGroup/FormControl 中存在的验证器
在自定义 Angular 组件中访问 FormControl