Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 角度:带有ControlValueAccessor的自定义输入_Javascript_Angular_Typescript_Components_Angular Reactive Forms - Fatal编程技术网

Javascript 角度:带有ControlValueAccessor的自定义输入

Javascript 角度:带有ControlValueAccessor的自定义输入,javascript,angular,typescript,components,angular-reactive-forms,Javascript,Angular,Typescript,Components,Angular Reactive Forms,如果自定义组件是另一个组件下的包装器,我不确定如何使用它 比如: 如果我有这样一个结构: ComponentA_withForm | --ComponentA11_withCustomInput 一切都很好 但是对于我的情况(大量异步数据),我需要一个包装器。。。有没有可能做到这一点 这是我的小提琴代码: 组成部分A: import { Component } from '@angular/core'; import { FormBuilder } from '@angular/forms';

如果自定义组件是另一个组件下的包装器,我不确定如何使用它

比如:

如果我有这样一个结构:

ComponentA_withForm
|
--ComponentA11_withCustomInput
一切都很好

但是对于我的情况(大量异步数据),我需要一个包装器。。。有没有可能做到这一点

这是我的小提琴代码:

组成部分A:

import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `<form [formGroup]="form"><custom-input-wrapper formControlName="someInput"></custom-input-wrapper></form> <p>value is: {{formVal | json}}</p>`
})
export class AppComponent {
  form = this.fb.group({
    someInput: [],
  });

  get formVal() {
    return this.form.getRawValue();
  }

  constructor(private fb: FormBuilder) { }
}
从'@angular/core'导入{Component};
从'@angular/forms'导入{FormBuilder};
@组成部分({
选择器:“我的应用程序”,
模板:`值为:{{formVal | json}}

` }) 导出类AppComponent{ form=this.fb.group({ someInput:[], }); 获取formVal(){ 返回此.form.getRawValue(); } 构造函数(私有fb:FormBuilder){} }
组件1:

import { Component } from '@angular/core';

@Component({
  selector: 'custom-input-wrapper',
  template: '<custom-input></custom-input>',
})
export class CustomInputWrapperComponent {
  constructor() { }
}
从'@angular/core'导入{Component};
@组成部分({
选择器:“自定义输入包装器”,
模板:“”,
})
导出类CustomInputWrapperComponent{
构造函数(){}
}
组件11:

import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'custom-input',
  template: `Hey there! <button (click)="inc()">Value: {{ value }}</button>`,
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomInputComponent),
    multi: true,
  }],
})
export class CustomInputComponent implements ControlValueAccessor {

  private value = 0;

  writeValue(value: number): void {
    this.value = value;
  }

  registerOnChange(fn: (_: any) => void): void {
    this.onChangeFn = fn;
  }

  registerOnTouched(fn: any): void {
  }

  inc() {
    this.value = this.value + 1;
    this.onChangeFn(this.value);
  }

  onChangeFn = (_: any) => { };
}
从'@angular/core'导入{Component,forwardRef};
从'@angular/forms'导入{ControlValueAccessor,NG_VALUE_ACCESSOR};
@组成部分({
选择器:“自定义输入”,
模板:`Hey there!Value:{{{Value}}`,
供应商:[{
提供:NG_值访问器,
useExisting:forwardRef(()=>CustomInputComponent),
多:是的,
}],
})
导出类CustomInputComponent实现ControlValueAccessor{
私有值=0;
writeValue(值:number):无效{
这个值=值;
}
registerOnChange(fn:((任意)=>void):void{
this.onChangeFn=fn;
}
注册人(fn:任何):无效{
}
公司(){
this.value=this.value+1;
this.onChangeFn(this.value);
}
onChangeFn=((_u1;:any)=>{};
}
这里我有一个工作样本:

因此:基本上,删除和重构代码以不使用
CustomInputWrapperComponent
可以让我的代码正常工作。但是我需要这个包装器,我不知道如何传递
formControlName


我不想要传递父formGroup:)的脏解决方案。

因为您不想要脏解决方案;),您也可以在
CustomInputWrapperComponent
中实现
ControlValueAccessor
。这样,父级中的任何更改都将反映在子级中,子级中的任何更改也将反映在父级中,只需几行代码

包装组件

@Component({
  selector: 'custom-input-wrapper',
  template: '<custom-input [formControl]="value"></custom-input>',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomInputWrapperComponent),
    multi: true,
  }]
})
export class CustomInputWrapperComponent implements AfterViewInit, ControlValueAccessor  {
  public value = new FormControl();

  constructor() { }

  ngAfterViewInit() {
    this.value.valueChanges.subscribe((x) => {
      this.onChangeFn(x);
    });
  }

  writeValue(value: number): void {
    this.value.setValue(value);
  }

  registerOnChange(fn: (_: any) => void): void {
    this.onChangeFn = fn;
  }

  registerOnTouched(fn: any): void {
  }

 onChangeFn = (_: any) => { };
}
@组件({
选择器:“自定义输入包装器”,
模板:“”,
供应商:[{
提供:NG_值访问器,
useExisting:forwardRef(()=>CustomInputWrapperComponent),
多:是的,
}]
})
导出类CustomInputWrapperComponent在ViewInit、ControlValueAccessor之后实现{
public value=new FormControl();
构造函数(){}
ngAfterViewInit(){
this.value.valueChanges.subscribe((x)=>{
这个。onChangeFn(x);
});
}
writeValue(值:number):无效{
this.value.setValue(值);
}
registerOnChange(fn:((任意)=>void):void{
this.onChangeFn=fn;
}
注册人(fn:任何):无效{
}
onChangeFn=((_u1;:any)=>{};
}
父模板

<form [formGroup]="form"><custom-input-wrapper formControlName="someInput"></custom-input-wrapper></form> <p>value is: {{formVal | json}}</p>
值为:{formVal|json}


我在这里做了一个stackbitz演示-

您不能在
自定义输入包装上使用
formControlName
,因为它没有实现
ControlValueAccessor
。在
自定义输入包装器
上实现
ControlValueAccessor
可能是一个解决方案,但似乎有些过分。相反,将控件作为
@input()
从formGroup传递到
自定义输入包装器
,并将输入的formControl传递到
自定义输入

应用程序组件

@组件({
选择器:“我的应用程序”,
模板:`值为:{{formVal | json}}

` }) 导出类AppComponent{ form=this.fb.group({ someInput:[], }); 获取formVal(){ 返回此.form.getRawValue(); } 构造函数(私有fb:FormBuilder){} }
自定义输入包装器.component

@组件({
选择器:“自定义输入包装器”,
模板:“”,
})
导出类CustomInputWrapperComponent{
@Input()formCtrl:AbstractControl;
构造函数(){}
}

下面是一个正在运行的演示

为什么不在
CustomInputWrapperComponent
中实现
ControlValueAccessor
?@abd995我认为这也是一种肮脏的方式:)我认为这是您可能拥有的最干净的解决方案。我猜传入表单控件或表单组是肮脏的解决方案。正如OP已经提到的<代码>我不想要传递父formGroup的脏解决方案
。将formGroup作为输入传递可能不是他想要的解决方案。Angular docs声明“ControlValueAccessor定义了一个接口,充当Angular forms API和DOM中本机元素之间的桥梁”。依我看,在
CustomInputWrapperComponent
中实现
ControlValueAccessor
是一个肮脏的解决方案,因为
CustomInputWrapperComponent
中没有本机元素需要与Angular Forms API桥接。如果可能,您可以将代码的相关部分添加到答案中吗?如果链接不再起作用,那么只有链接的答案就变得无关紧要了,在stackblitz演示的情况下,它也是观众寻找相关部分的工作。我强烈建议您在代码中添加注释,以防您为其他人编写注释(如有人在这里询问堆栈溢出)。@SaschaM78我已在答案中添加了代码的某些部分。非常感谢您添加了相关的代码部分,这使答案更容易理解。@abd995感谢此解决方案,它非常有效。我唯一修改的是,我没有使用
valueChanges
触发包装器组件的onchange fn,而是使用
ViewChild
抓取内部组件,然后使用它触发onchange,比如:
this.innerComponent.registerTouched(this.onTouched)罪恶
<form [formGroup]="form"><custom-input-wrapper formControlName="someInput"></custom-input-wrapper></form> <p>value is: {{formVal | json}}</p>